Token-saving contracts for your codebase
Project description
FileSpecContractor (fsc)
Token-saving contracts for your codebase.
fsc is a command-line tool that generates descriptive specifications for your code files - compact "contracts" that help LLMs understand your project without burning through free-tier token limits.
Why?
Free LLM models have strict context limits. Feeding them your entire codebase is expensive and often impossible. fsc creates lightweight .fsc.md files that capture the public API and critical implementation details of each file - enough for an agent to work with, small enough to fit in context.
Born from the frustration of trying to vibe-code on a student laptop.
Installation
# Install with uv
uv tool install file_spec_contractor
# Or with pip
pip install file_spec_contractor
After installation, the fsc command is available globally:
fsc --help
Usage
# Set up configuration with defaults
fsc init
# Init with custom settings
fsc init --extensions .py --extensions .kt --language ru
# Init with a different provider
fsc init --provider deepseek
# Overwrite existing config
fsc init --yes
# Remove all fsc artifacts (.fsc/ and *.fsc.md files)
fsc deinit
# Recreate configuration from scratch (deinit + init)
fsc reinit
# Reinit with custom flags
fsc reinit --extensions .py --extensions .kt --language ru
# Generate specifications for current directory (scan mode, batch by default)
fsc generate
# Generate for specific files
fsc generate --file src/machine.py
# Generate with custom extensions
fsc generate --extensions .py .kt
# Force per-file mode with parallel requests
fsc generate --force-per-file -c 5
# Preview what would be generated (no files written)
fsc generate --dry-run --verbose
# Enable verbose output
fsc generate --verbose
# Russian language specifications
fsc generate --language ru
Generation Modes
| Mode | Flag | Behaviour |
|---|---|---|
| batch | (default) | All files in a single LLM request. Consistent, cross-referenced specifications. |
| per-file sequential | --force-per-file |
Each file separately, one at a time. |
| per-file parallel | --force-per-file -c N |
N files simultaneously via thread pool. Fastest for large projects. |
If batch mode fails to produce parsable output, fsc automatically falls back to per-file generation.
Commands
| Command | Description |
|---|---|
init |
Create .fsc/ with config and prompt. Accepts all genration flags to customize initial config. Warns if already configured. |
deinit |
Remove .fsc/ and all *.fsc.md files from the project. |
reinit |
deinit + init. Accepts all the same flags as init. |
generate |
Generate .fsc.md specifications. |
Options
All options below are available on generate, init, and reinit (except --file, --dry-run, --verbose which are generate-only).
| Option | Description |
|---|---|
-y, --yes |
Skip confirmations, overwrite existing files (init/reinit) |
--file |
Specific files to generate specs for (generate only, repeatable) |
--extensions |
File extensions to include (default: .py) |
--exclude-dirs |
Directories to skip |
--exclude-files |
File patterns to skip |
--provider |
LLM provider: openrouter (default) or deepseek |
--api-key |
API key for the selected provider |
--output-mode |
mirror (default), adjacent, or batch |
--output-dir |
Output directory for mirror/batch mode (default: .fsc/specs) |
--batch-size |
Files per folder in batch mode (default: 50) |
--prompt-file |
Custom system prompt file |
--language |
Output language: en (default) or ru |
-c, --concurrency |
Parallel requests for per-file mode (default: 1) |
--force-per-file |
Force per-file generation instead of batch |
-f, --force |
Regenerate all specs, ignoring cache |
--dry-run |
Preview without writing files or calling API (generate only) |
--verbose |
Detailed output (generate only) |
Configuration
fsc looks for configuration in this order (later sources override earlier ones):
- CLI arguments (highest priority)
.fsc/config.tomlin your project root~/.config/fsc/config.tomlfor user-wide settings
Creating config
fsc init
This creates:
.fsc/config.toml- project configuration.fsc/PROMPT.md- custom system prompt (optional, built-in prompt is used as fallback)
Example .fsc/config.toml
# Which files to scan and which to skip
[project]
extensions = [".py", ".kt"]
exclude_dirs = [".venv", "venv", ".git", "__pycache__", "tests"]
exclude_files = ["setup.py", "conftest.py"]
# Output language and mode
[output]
language = "en" # "en" or "ru"
output_mode = "mirror" # "mirror", "adjacent", or "batch"
output_dir = ".fsc/specs"
batch_size = 50 # files per folder (batch mode)
# LLM provider
[api]
provider = "openrouter" # "openrouter" or "deepseek"
# Custom system prompt file (relative to project root)
[prompt]
file = ".fsc/PROMPT.md"
# Generation runtime settings
[runtime]
concurrency = 1 # parallel threads for per-file mode
force_per_file = false # skip batch mode, use per-file
API Key
API keys are never stored in config files. Three ways to provide them (in priority order):
- CLI flag -
--api-key(highest priority) - Environment variable -
OPEN_ROUTER_API_KEY/DEEPSEEK_API_KEY .envfile in project root (lowest priority)
OpenRouter (default):
# Option 1: CLI flag
fsc generate --api-key sk-or-v1-...
# Option 2: environment variable
export OPEN_ROUTER_API_KEY=sk-or-v1-...
# Option 3: .env file
echo "OPEN_ROUTER_API_KEY=sk-or-v1-..." > .env
DeepSeek (alternative):
fsc generate --provider deepseek --api-key sk-...
# or: export DEEPSEEK_API_KEY=sk-...
# or: echo "DEEPSEEK_API_KEY=sk-..." > .env
Providers
| Provider | Model | Free | Env var |
|---|---|---|---|
| OpenRouter (default) | openai/gpt-oss-120b:free |
yes | OPEN_ROUTER_API_KEY |
| DeepSeek | deepseek-chat |
yes | DEEPSEEK_API_KEY |
Switch provider via config or CLI:
fsc generate --provider deepseek
Output Modes
| Mode | Behaviour |
|---|---|
adjacent |
Saves file.fsc.md right next to file.py |
mirror |
Saves to output_dir, preserving directory structure (e.g., src/machine.py → .fsc/specs/src/machine.fsc.md) |
batch |
Groups specs into numbered folders batch-1/, batch-2/, etc. File names encode the original path (e.g., src/machine.py → src__machine.fsc.md). Folder size controlled by batch_size (default: 50). |
Batch mode example (batch_size = 50, 120 files):
.fsc/batches/
├── batch-1/
│ ├── src__controllers__UserController.fsc.md
│ └── ... (49 more files)
├── batch-2/
│ ├── src__models__Product.fsc.md
│ └── ... (49 more files)
└── batch-3/
└── ... (20 files)
Configure via CLI or config:
fsc init --output-mode batch --batch-size 100
fsc generate --output-mode batch --batch-size 50
# .fsc/config.toml
[output]
output_mode = "batch"
output_dir = ".fsc/batches"
batch_size = 50
Prompt
fsc sends a system prompt to the LLM that defines the specification format. Built-in prompts are versioned per language: fsc_en_5.md, fsc_ru_5.md. The latest version is always used. Resolution order:
--prompt-fileCLI argument.fsc/PROMPT.mdin project root- Built-in prompt from the package
If no prompt file is found, a warning is shown and the built-in prompt is used.
How It Works
- Scans your project for files matching configured extensions
- For each file, sends the code with a system prompt to the LLM provider
- The LLM generates a structured
.fsc.mdspecification - Saves the specification - ready to be fed to any LLM agent
Specification Format
Each generated spec follows this structure:
- Purpose - what this file does
- Dependencies - external libs and internal modules
- Public API - all public methods with signatures and notes
- Implementation Notes - sentinels, patterns, non-obvious details
- Handle with Care - contracts that are easy to break
- Code Style - conventions used in this file
Requirements
- Python 3.12+
- uv for dependency management
- OpenRouter or DeepSeek API key (see API Key)
.envfile support via python-dotenv
Tech Stack
| Component | Library |
|---|---|
| CLI | Typer |
| Validation | Pydantic |
| Logging | Rich |
| HTTP | httpx |
| Config | python-dotenv |
| Testing | pytest |
Development
# Clone and install in editable mode
git clone https://github.com/UmbrellaLeaf5/file_spec_contractor.git
cd file_spec_contractor
uv sync
# Run all tests (63 tests)
uv run pytest
# Run specific test file
uv run pytest tests/test_deepseek.py -v
# Run CLI in dev
uv run fsc --help
# Build package
uv build
Roadmap
- Core CLI with
init,generate,deinit,reinitcommands - DeepSeek API integration
- OpenRouter API integration (free
gpt-oss-120bmodel) - Multi-provider support with
--providerflag - Batch generation mode (all files in one request with fallback)
- Parallel per-file generation (
--force-per-file -c N) - Spec caching with
--forceto regenerate - Configuration file support (TOML) with Pydantic validation
-
.envfile support for API keys (via python-dotenv) - All config flags available on
init,reinit, andgenerate - Batch output mode, mirror, and adjacent
- Prompt resolution (project file → built-in fallback, per-language)
- Multi-language prompt support (en, ru)
- Installable CLI entry point (
fsc) - Graceful shutdown on Ctrl+C
- 63 tests (unit, integration, CLI)
-
--updateflag for incremental regeneration - Rich progress bars for large projects
- Local model support (Ollama, LM Studio)
- Publish to PyPI (
pip install file_spec_contractor) - VS Code extension (generate specs from context menu / command palette)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file file_spec_contractor-0.2.5.tar.gz.
File metadata
- Download URL: file_spec_contractor-0.2.5.tar.gz
- Upload date:
- Size: 67.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b694f8887f6f51eaf8f301bc1c3ef3a8af2fa068bec235511be80894a214c35c
|
|
| MD5 |
9804fbdb96a038498da2438e4204f60d
|
|
| BLAKE2b-256 |
7b81adbd8d70e94ca26139965aaeb761a4d7074186cc4fe72d8dc7b5c441b824
|
Provenance
The following attestation bundles were made for file_spec_contractor-0.2.5.tar.gz:
Publisher:
publish.yml on UmbrellaLeaf5/file_spec_contractor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
file_spec_contractor-0.2.5.tar.gz -
Subject digest:
b694f8887f6f51eaf8f301bc1c3ef3a8af2fa068bec235511be80894a214c35c - Sigstore transparency entry: 1394983202
- Sigstore integration time:
-
Permalink:
UmbrellaLeaf5/file_spec_contractor@8f0da6280843bbcc8c768e04a37a466ba4418e80 -
Branch / Tag:
refs/tags/0.2.5 - Owner: https://github.com/UmbrellaLeaf5
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8f0da6280843bbcc8c768e04a37a466ba4418e80 -
Trigger Event:
push
-
Statement type:
File details
Details for the file file_spec_contractor-0.2.5-py3-none-any.whl.
File metadata
- Download URL: file_spec_contractor-0.2.5-py3-none-any.whl
- Upload date:
- Size: 44.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c55909e6cbb76f513db1a98a829103d4368185a882ecee926e3509e25dc75d6e
|
|
| MD5 |
226365c9b7ad40731111facb5887e75b
|
|
| BLAKE2b-256 |
3d1fed91c531c15e07c0f4bb455628339a7ebc7fc1a01e0fa2531e0d2c159eea
|
Provenance
The following attestation bundles were made for file_spec_contractor-0.2.5-py3-none-any.whl:
Publisher:
publish.yml on UmbrellaLeaf5/file_spec_contractor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
file_spec_contractor-0.2.5-py3-none-any.whl -
Subject digest:
c55909e6cbb76f513db1a98a829103d4368185a882ecee926e3509e25dc75d6e - Sigstore transparency entry: 1394983210
- Sigstore integration time:
-
Permalink:
UmbrellaLeaf5/file_spec_contractor@8f0da6280843bbcc8c768e04a37a466ba4418e80 -
Branch / Tag:
refs/tags/0.2.5 - Owner: https://github.com/UmbrellaLeaf5
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8f0da6280843bbcc8c768e04a37a466ba4418e80 -
Trigger Event:
push
-
Statement type: