Download Code-agent-main/README.md from Yazhiniyan/YCode: direct link, hf CLI and curl.
- Browser
- Download file 37.6 kB
-
https://huggingface.co/Yazhiniyan/YCode/resolve/main/Code-agent-main/README.md
- Command line
-
hf download hf://Yazhiniyan/YCode/Code-agent-main/README.md
-
curl -L -o README.md https://huggingface.co/Yazhiniyan/YCode/resolve/main/Code-agent-main/README.md
YCode
βββ βββ βββββββ βββββββ βββββββ ββββββββ
ββββ βββββββββββββββββββββββββββββββββββββ
βββββββ βββ βββ ββββββ βββββββββ
βββββ βββ βββ ββββββ βββββββββ
βββ βββββββββββββββββββββββββββββββββ
βββ βββββββ βββββββ βββββββ ββββββββ
YCode is an AI coding agent that runs in your terminal. Start it inside a project, describe a task in plain English, and it works through it: it looks around the repository, makes a short plan, edits files, runs your tests and build, reads any failures, fixes them, and then tells you what changed.
YCode works out of the box with no API key and no training. By default it answers with YCode-LM, its own coding language model, trained from scratch and shipped in this repository (models/). Clone, install, and run ycode: nothing to sign up for, no key to paste, nothing sent over the network. See Answering without an API key.
YCode-LM is the only model YCode needs. If you also want full autonomous coding (reading, editing and running files in your project, as in the example below), you can optionally plug in Claude: see Using Claude (optional). Everything else always runs locally: the tool system, the permission checks and the terminal UI. The model sits behind a small provider interface, so you can add other LLM providers without rewriting the agent.
With Claude (--provider anthropic), YCode works through whole tasks:
ycode> Fix the failing add() test
β Plan
βΈ 1. Read calc.py
β 2. Fix add
β 3. Run tests
β Reading calc.py
β Read calc.py (2 of 2 lines)
β Editing calc.py
β Edited calc.py (+1 -1)
@@ -1,2 +1,2 @@
def add(a, b):
- return a - b
+ return a + b
β Running `python -m pytest -q`
β Succeeded (exit code 0, 0.3s)
Fixed `add` in calc.py; pytest passes (1 test).
Changes:
M calc.py
Commands:
β python -m pytest -q
β YCode completed the task. (5 steps)
Features
- Terminal first. Uses Rich for output: spinners, streamed Markdown, syntax-highlighted diffs. Uses prompt_toolkit for input: persistent history, multiline editing, and tab completion for
/commands. - Autonomous agent loop. The model can make many tool calls per task, parallel calls included, until it is done. A configurable step limit (default 50) stops runaway loops.
- Planning. For non-trivial work the model writes a short plan through an
update_plantool and keeps it current. For trivial requests it skips the plan. - Verification. The model picks verification commands from your project type (
npm test,pytest,cargo test, ...), reads failures and iterates. It is told never to claim success it did not verify. - Tools:
read_file,write_file,edit_file,list_directory,search_files,find_files,run_command,git_status,git_diff,git_log,git_branch,update_plan. - Security. Commands are classified as SAFE, REQUIRES_APPROVAL or BLOCKED. Risky ones need an explicit
y. File access is confined to the workspace, and API keys are stripped from the environment that commands run in. - Repository awareness. Detects Node.js, TypeScript, JavaScript, React, Next.js, Vue, Python, Java, Kotlin, C/C++, Rust, Go, Flutter/Dart, Ruby and PHP projects, plus the package manager and the likely test and build commands. Large generated directories are ignored.
- Diff awareness. After each task YCode summarizes the changed files and the commands it ran.
/diffshows the full diff. - Project instructions. A
YCODE.mdfile in the repository is loaded into the agent's instructions. - Layered configuration: global and per-project TOML files, environment variables and CLI flags.
- No API key needed. The default provider is YCode's own bundled model. It answers Python documentation questions exactly from Python's built-in docs, and writes functions that are checked to compile and define what you asked for. Everything runs offline.
- Model-agnostic core. The agent depends only on
LLMProvider. There are two implementations: your own local model (default) and Claude (optional). - Your own LLM.
ycode-lmbuilds a byte-level BPE tokenizer and a GPT-style transformer from scratch, pretrains it on code, and instruction-tunes it to answer programming questions. Four trained versions ship with the repository, up to the 1.5B-parameter v5.
Architecture
ββββββββββββββββ
β YCode CLI β cli.py, commands.py, ui/
ββββββββ¬ββββββββ
β
ββββββββΌββββββββ
β Agent Engine β agent/loop.py, planner.py, context.py, prompts.py
ββββββββ¬ββββββββ
β
ββββββββββΌβββββββββ
β LLM Provider β llm/base.py (interface), llm/anthropic.py
ββββββββββ¬βββββββββ
β
Claude API
β
ββββββββββΌβββββββββ
β Tool Execution β tools/ (+ security/permissions.py)
ββββββββββ¬βββββββββ
ββββββββββββββΌβββββββββββββ
βΌ βΌ βΌ
Filesystem Terminal Git
ycode/
βββ __main__.py # python -m ycode
βββ cli.py # argument parsing, REPL, graceful shutdown
βββ app.py # wires config, context, permissions, tools, provider, agent, UI
βββ commands.py # /help /clear /status /diff /files /model /plan /approval /exit
βββ config.py # layered TOML + env + CLI configuration
βββ errors.py # user-facing error hierarchy (no raw tracebacks)
βββ agent/
β βββ loop.py # the agent loop, step limit, interruption handling
β βββ planner.py # Plan model + update_plan tool
β βββ context.py # project detection, YCODE.md loading
β βββ prompts.py # system prompt
βββ llm/
β βββ base.py # provider-neutral messages, ToolSpec, LLMProvider
β βββ anthropic.py # Claude via the official anthropic SDK (streaming)
β βββ local.py # your own YCode-LM model (answer-only, no API key)
βββ lm/ # YCode-LM: the from-scratch model; assist.py answers docs questions and checks code
β βββ tokenizer.py # byte-level BPE tokenizer for code
β βββ model.py # GPT transformer: RoPE, RMSNorm, SwiGLU, KV-cache sampling
β βββ data.py # corpus collection, instruction-pair extraction, encoding
β βββ train.py # pretraining + instruction tuning, checkpoints, resume
β βββ optim.py # Muon optimizer (v3) + AdamW wiring
β βββ evaluate.py # bits/byte on held-out code, pass@k on executed problems
β βββ generate.py # inference (chat + completion, streaming)
β βββ cli.py # the `ycode-lm` command
βββ tools/
β βββ base.py # Tool, ToolRegistry (validation + dispatch), ToolResult
β βββ filesystem.py # read/write/edit/list
β βββ search.py # regex content search, glob file search
β βββ terminal.py # run_command (timeouts, output capture, Ctrl+C)
β βββ git.py # git helpers + read-only git tools
βββ security/
β βββ permissions.py # command classifier, PathGuard, PermissionManager
βββ ui/
βββ banner.py # ASCII banner
βββ console.py # Rich renderer (implements AgentEvents)
βββ prompts.py # prompt_toolkit input with history/multiline
The dependencies point one way. The agent knows nothing about Rich or Anthropic: it talks to an LLMProvider and reports progress through AgentEvents callbacks. The UI implements those callbacks. Tools don't know about the model.
Adding a provider: subclass LLMProvider in ycode/llm/, translate the neutral UserMessage/AssistantMessage/ToolResultsMessage types to your API's format, and register it in ycode/llm/__init__.py:create_provider. Assistant messages carry an opaque provider_data field. Your provider can use it to replay its own native content exactly, which Claude needs for its thinking blocks.
Requirements
- Python 3.10+
- About 4 GB of free RAM for the default model, YCode-LM v5 (1.5B parameters). With less, YCode uses the smaller v4 (about 1 GB) automatically.
- Git, to clone the repository (it contains the trained models) and for the git features
That's all. No API key, no account and no internet connection are needed to run YCode.
Installation
git clone https://github.com/yazhiniyanMS/Code-agent.git
cd Code-agent
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e . # includes PyTorch for the built-in model
ycode # start asking questions: no API key, no training
This installs a ycode command. python -m ycode works too. Install from the clone (as above) rather than from a bare package: the trained models live in the repository's models/ folder. To keep them elsewhere, set YCODE_MODELS_DIR.
Optional extras:
pip install -e ".[hf]" # Hugging Face: transformers, huggingface_hub, safetensors, accelerate
pip install -e ".[claude]" # Claude support (only if you want --provider anthropic)
pip install -e ".[dev]" # tests
Answering without an API key
ycode uses YCode's own model by default. Every answer goes through three steps:
- Documentation questions are answered exactly. "What does
len()do?", "How do I usejson.loads?", "What isyield?", "Explainos.path.join", "What's the difference between a list and a tuple?": YCode looks the names up in Python's own built-in documentation, which ships with every Python install, and shows the signature and the official description. Only built-in names and standard-library modules are looked up. Your project's code is never imported. - "Write a function
name(...)" requests are checked. The model writes up to four candidates. YCode keeps the first one that compiles and defines the function you asked for. Candidates are only parsed, never run. The answer says that the name and syntax were checked, not the logic. - Everything else goes to the model as a normal chat turn.
ycode> What does the zip() function do?
zip(*iterables, strict=False) (class)
Yield tuples until an input is exhausted.
>>> list(zip('abcdefg', range(3), range(4)))
[('a', 0, 0), ('b', 1, 1), ('c', 2, 2)]
...
(From Python's built-in documentation.)
Choosing a model. YCode picks a model in this order: one you trained yourself (~/.ycode/models/ycode-lm), otherwise the bundled v5. If less than 4 GB of memory is free, it uses v4 instead. Pick one explicitly with --local:
ycode # default: YCode-LM v5 (1.5B parameters), loaded in 16-bit: about 3 GB of RAM
ycode --local v4 # YCode-LM v4 (100M parameters): much faster on a CPU
ycode --local path/to/dir # any model you trained
You can also set local_model = "v4" in ~/.ycode/config.toml or YCODE_LOCAL_MODEL=v4. v5 models code best of all versions (see the results), but a 1.5B model is slow on a CPU: expect a few tokens per second, so a long answer can take a minute or more. On a slow machine, v4 is the practical choice.
What to expect. The bundled models were trained from scratch on a CPU, with a tiny fraction of the data and compute behind commercial assistants. They write well-formed Python, but their own code is often wrong, so test it. The local model also runs in answer-only mode: it answers in its reply but cannot read, edit or run files in your project. For autonomous work on a codebase, use Claude.
Hugging Face (optional)
pip install -e ".[hf]" installs the Hugging Face libraries: transformers, huggingface_hub, safetensors and accelerate. With them, ycode-lm push-hf publishes a model to your Hugging Face account, and ycode-lm autotrain trains on GPUs while saving checkpoints there.
These commands need a Hugging Face access token with Write access, created at https://huggingface.co/settings/tokens. Give it to YCode in either of these ways:
export HF_TOKEN=hf_... # for this shell (or put HF_TOKEN=... in ~/.ycode/.env)
hf auth login # or save it once with the Hugging Face CLI
Then, for example:
ycode-lm push-hf --model models/ycode-lm-v5 --repo your-name/ycode-lm-v5 --public
The token is only used to upload models. Running YCode never needs it. Keep it secret: never commit it, and don't paste it into a chat.
Using Claude (optional)
YCode never needs Claude. If you want it for autonomous work on a codebase, install the extra with pip install -e ".[claude]", then run ycode --provider anthropic or set provider = "anthropic" in your config. YCode then reads ANTHROPIC_API_KEY. In order of precedence, the places it looks are:
- Your shell environment:
export ANTHROPIC_API_KEY=sk-ant-... - A
.envfile in the project you run YCode in ~/.ycode/.env, which applies to every project- The
.envin the YCode checkout itself, which is handy withpip install -e .
Values that are already set are never overridden. Any of these work too: ANTHROPIC_AUTH_TOKEN, an ant auth login profile, or workload identity federation. If you ask for Claude and YCode finds no credentials, it shows the banner, prints a clear error and exits with status 1. Without --provider anthropic, YCode never asks for a key.
YCode never prints your key. It also removes ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN from the environment of commands it runs, so a stray env can't leak the key to the model. Never commit .env. The included .gitignore excludes it.
Your own LLM (YCode-LM, no API key)
YCode-LM is a programming language model you train from scratch on your own machine. Nothing is downloaded: the tokenizer, the model architecture and the training loop are all in this repository (ycode/lm/), and the data is code you already have.
What it is:
- Tokenizer: byte-level BPE (
ycode/lm/tokenizer.py) trained on your corpus. A code-aware pre-tokenizer turns indentation runs, identifiers and operators into compact tokens. - Model: a decoder-only transformer (
ycode/lm/model.py) with rotary position embeddings, RMSNorm, SwiGLU MLPs, tied embeddings and a KV cache for fast sampling. Version 2 (the default) adds grouped-query attention, which shares key/value heads for a 4Γ smaller KV cache and faster generation, and QK-norm, which keeps attention stable at higher learning rates. v1 checkpoints still load. - Training data: any code directories you point it at. With no
--source, it uses the Python standard library, which every Python install has. - Two training stages:
Pretraining: next-token prediction on code.
Instruction tuning (SFT): teaches the model to answer. The data is generated automatically from the real code in your corpus, so every answer is real code:
- write a function from its description
- explain a function
- complete a function from its signature and docstring
- write a docstring
- explain a class
- find and fix a bug: YCode-LM injects realistic one-token bugs (
<vs<=,+vs-, off-by-one,and/or,True/False). The original code is the fix, so these examples are correct by construction.
You can add your own pairs as JSONL (
{"prompt": ..., "response": ...}) with--sft-data.
What v2 improves:
| v1 | v2 | |
|---|---|---|
| Attention | multi-head | grouped-query (smaller cache) + QK-norm |
| LR schedule | cosine over steps; cut short by --minutes |
warmup-stable-decay. Progress is the larger of steps done and time used, so a time-limited run always finishes its decay |
| End of pretraining | code only | anneals with 20% instruction data during the decay phase, so the model already knows the chat format before SFT |
| SFT batches | one example per row, padded | several examples packed per row, so no compute is wasted on padding |
| Data | write/explain pairs | + bug fixing, completion, docstrings, classes; de-duplicated prompts; licence headers stripped |
| Data prep | single process | tokenization on all CPU cores |
| Measurement | loss only | ycode-lm eval: bits per byte on held-out code + pass@k on 30 executed coding problems |
The included models (no training needed). The repository ships four trained models. ycode uses v5 by default (v4 when memory is short):
| Model | Params | Size | Card |
|---|---|---|---|
| YCode-LM v5 (default) | 1,523M | 2.9 GB in 103 shards | models/ycode-lm-v5 |
| YCode-LM v4 | 100M | 200 MB in 5 shards | models/ycode-lm-v4 |
| YCode-LM v3 | 40.8M | 81.8 MB | models/ycode-lm-v3 |
| YCode-LM v2 | 7.7M | 15.6 MB | models/ycode-lm-v2 |
ycode --local v4 # or: ycode-lm chat --model models/ycode-lm-v4
Set up and train:
pip install -e . # PyTorch + NumPy are included
# 1. Build the dataset: collect code, train the tokenizer, create instruction pairs.
# --exclude keeps code out of training so you can evaluate on it later.
ycode-lm prepare --out data/ --source ~/my-projects --source /usr/lib/python3.11 --exclude '*/holdout/*'
# 2. Pretrain on code (bf16 on CPUs with AMX/AVX512-BF16, CUDA or Apple MPS when available)
ycode-lm train --data data/ --out models/base --preset v2-small --minutes 180
# 3. Instruction-tune it so it answers requests
ycode-lm sft --data data/ --init-from models/base --out ~/.ycode/models/ycode-lm --minutes 40
# 4. Measure it (compare several models by repeating --model)
ycode-lm eval --model ~/.ycode/models/ycode-lm --heldout path/to/unseen/code --samples 5
# 5. Use it
ycode-lm chat # quick Q&A in the terminal
ycode # inside YCode: your model in ~/.ycode/models/ycode-lm is used automatically
ycode --local models/chat # or point to any trained model
Other commands: ycode-lm sample --model models/base --prompt "def quicksort(" (raw code completion), ycode-lm info, ycode-lm export --model DIR --out DIR (slim bf16 copy for sharing, about 4Γ smaller than a training checkpoint), and ycode-lm train --resume (continue an interrupted run). Ctrl+C during training keeps the last checkpoint. Training options include --schedule wsd|cosine, --anneal-mix, --no-pack, --compile (torch.compile) and --grad-accum.
Version 3: the 40M-parameter model. --preset v3-40m uses the v2 architecture scaled to 40.8M parameters with a 1024-token context. It trains with the Muon optimizer by default: transformer weight matrices are updated with orthogonalized momentum (NewtonβSchulz iterations), while embeddings and norms stay on AdamW. On small transformers, Muon reaches a given loss with fewer tokens, which matters most when compute is the bottleneck. Use --optimizer adamw to switch back.
ycode-lm train --data data/ --out models/v3-base --preset v3-40m --compile --minutes 480
ycode-lm sft --data data/ --init-from models/v3-base --out ~/.ycode/models/ycode-lm --compile --minutes 60
In an A/B test (same model, data, seed and 600 steps), Muon reached a held-out loss of 4.13 against AdamW's 4.26, for 14% more wall-clock per step at that tiny size; the overhead shrinks as models grow.
A 40M model wants far more data and compute than a CPU can supply. The compute-optimal budget is about 800M training tokens, while 8 hours on a 4-core CPU covers about 50M. On a single consumer GPU, the same run takes hours instead of days.
Measured results (v1 β v5). All five models were evaluated the same way. Bits per byte is measured on 11 packages none of them saw in training. The code tasks are executed against unit tests:
| v1 | v2 | v3 | v4 | v5 | |
|---|---|---|---|---|---|
| Parameters | 6.9M | 7.7M | 40.8M | 100M | 1,523M |
| Training | ~41M tokens | ~82M tokens | ~60M tokens (Muon) | grown from v3 + ~24.6M tokens | grown from v4 + ~2.5M tokens (Lion, CPU) |
| Bits per byte on held-out code | 1.095 | 0.966 | 0.857 | 0.814 | 0.758 |
| Write a function, pass@1 (30 problems) | 0 / 30 | 0 / 30 | 0 / 30 | 1 / 30 | 0 / 30 |
| Fix an injected bug, fix@1 (15 functions) | 0 / 15 | 5 / 15 | 4 / 15 | 5 / 15 | 4 / 15 |
Each version models real code better than the last; v5's 7% gain over v4 is the largest step so far, but it has not yet turned into solving more tasks (it is badly under-trained for its size). v2βv4 write short, well-formed answers and can find and fix simple bugs ("The bug is in result = 1. It should be result = 0."), while v1 falls into repetition loops. v4 is the first to write a correct function from a description (square β return x * x). Writing functions reliably needs much more training data and compute than a CPU provides.
Growing models. ycode-lm grow --model v3 --out v4-init --layers 34 deepens a trained model by inserting copies of existing blocks with zeroed output projections. The result computes exactly the same function, so train --init-from v4-init continues from everything the small model learned. v4 was built this way. For files over GitHub's 100 MB limit, export --max-shard-mb 45 splits the weights into shards that load transparently.
For long runs on machines that may be interrupted, train in segments: --until-step N stops and saves, --resume continues with the same LR schedule, and --save-interval N saves cheaply between evaluations.
Version 5: 1.5 billion parameters, trained on a CPU. v5 (--preset v5-1.5b, 34 layers Γ 2048 wide, 32 query / 8 KV heads, 1,523M parameters) is v4 grown 4Γ in width with ycode-lm grow --width 2048, so it starts out computing exactly what v4 computed and keeps everything v4 learned. A 1.5B model normally needs ~18 GB just for fp32 weights, gradients and optimizer state. v5 trains in 15 GB of RAM with a low-memory mode (--optimizer lion):
- Lion optimizer: the update is the sign of a momentum, so it keeps one state per weight instead of AdamW's two, stored in bf16 (3 GB).
- Updates inside backward: each weight is updated the moment its gradient is ready, and the gradient is freed at once. A full set of gradients (6 GB) never exists.
- Gradient checkpointing, bf16 autocast without the cast-weight cache (which would be another 3 GB copy), and memory-mapped checkpoint loading.
ycode-lm grow --model models/ycode-lm-v4 --out models/v5-base --width 2048 --version 5
ycode-lm train --data data/ --out models/v5-base --resume --steps 600 --batch-size 4 \
--optimizer lion --lr 3e-5 --grad-checkpoint --save-interval 20 --until-step 80
On 4 CPU cores this runs at about 55 tokens per second, so a day of training covers only a few million tokens. A 1.5B model would ideally see tens of billions. v5 therefore benefits most from GPUs. With several GPUs, --shard splits the weights, gradients and optimizer state across them (FSDP) so models too large for one GPU still train. Muon works on the sharded weights. ycode-lm autotrain drives a whole run across time-limited GPU sessions, saving checkpoints to Hugging Face. notebooks/kaggle_train_v5.ipynb does this on free Kaggle GPUs. To publish any model directory, use ycode-lm push-hf --model DIR --repo you/name.
Evaluation. ycode-lm eval reports:
- Bits per byte on code the model never saw. Lower is better. It is comparable across tokenizers, so v1, v2 and v3 compare fairly.
- pass@1 / pass@k on 30 small programming problems, plus fix@1 on 15 functions with one injected bug each. YCode-LM writes each solution or fix, and it is executed against unit tests in an isolated subprocess with a timeout. Only evaluate models you trained yourself, because generated code is run.
Model sizes (--preset; parameter counts are for an 8k vocabulary):
| Preset | Layers Γ width | Heads (KV) | Context | Params | Where to train |
|---|---|---|---|---|---|
v5-1.5b |
34 Γ 2048 | 32 (8) | 1024 | 1,523M | grow from v4; CPU with --optimizer lion (slow), or GPUs (--shard for several) |
v5-385m |
34 Γ 1024 | 16 (4) | 1024 | ~385M | grow from v4; a 16 GB GPU |
v4-100m |
34 Γ 512 | 8 (2) | 1024 | 100.0M | grow from v3 (ycode-lm grow); GPU recommended for training |
v3-40m |
13 Γ 512 | 8 (2) | 1024 | 40.8M | GPU ideal; CPU works but slowly (measured ~2.1k tok/s on 4 Xeon cores with bf16 + compile) |
v3-tiny |
3 Γ 64 | 4 (2) | 128 | ~0.7M | tests |
v2-tiny |
2 Γ 64 | 4 (2) | 128 | ~0.6M | tests / smoke runs |
v2-small (default) |
8 Γ 256 | 8 (2) | 512 | ~7.7M | laptop CPU, 2β4 h |
v2-base |
12 Γ 512 | 8 (2) | 1024 | ~38M | GPU |
v2-medium |
16 Γ 768 | 12 (4) | 1024 | ~107M | GPU, many hours |
v2-large |
24 Γ 1024 | 16 (4) | 2048 | ~274M | multi-hour GPU runs |
The v1 presets (tiny, small, base, medium, large) are still available.
Use --layers/--heads/--embd/--context to customize a preset.
Using it in YCode. The local model is YCode's default provider. Related settings: local_model (v2βv5 or a path), local_max_tokens and local_temperature. Nothing is sent over the network.
Be realistic about quality. Frontier coding models are trained on trillions of tokens with thousands of GPUs. A few-million-parameter model trained for an hour or two on a CPU learns real Python syntax, idioms and naming conventions, and can write small functions and short explanations. It will also often be wrong, repetitive or confused. Two consequences:
- Answer-only mode. In YCode, the local model runs in answer-only mode. It hasn't learned the tool-calling protocol, so it cannot read, edit or run files in your project. YCode shows a notice when it starts. Use Claude (
--provider anthropic) for autonomous coding tasks. - How to make it better: more and better data (your own repositories), a bigger preset, a GPU and longer training. The loss figures in
train_log.jsonshow whether it is still improving.
Usage
cd my-project
ycode # interactive session
ycode "add a --verbose flag to the CLI" # one-shot: run the task, then exit
ycode -p "explain src/auth.ts" # same, with -p
ycode --local v5 # pick a bundled model (v2-v5) or a model directory
ycode --provider anthropic # optional: use Claude (needs the [claude] extra and ANTHROPIC_API_KEY)
ycode --provider anthropic -m claude-sonnet-5-5 # pick a Claude model
ycode --approval-mode strict # approve every write and non-read-only command
ycode --yes # auto-approve risky commands (blocked ones stay blocked)
ycode -C ../other-project # run against another directory
In the interactive session:
| Key / command | Action |
|---|---|
| Enter | Send the request |
Esc+Enter (or a line ending in \) |
Insert a newline |
| Up / Down | History (stored in ~/.ycode/history) |
| Ctrl+C | Interrupt the running task; YCode kills any running command and returns to the prompt |
| Ctrl+C twice / Ctrl+D | Exit |
/help |
List commands |
/status |
Project, branch, modified files, model, steps used, token usage |
/diff [full] [path...] |
Show the git diff, with a stat summary if it is very large |
/files |
Changed files: working tree plus files written this session |
/model [id] |
Show or switch the model for this session |
/plan |
Show the current plan |
/approval [strict|normal|auto] |
Show or change the approval mode |
/clear |
Forget the conversation and clear the screen |
/exit, /quit |
Quit |
Slash commands are handled locally and are never sent to the model. Each request continues the same conversation, so a follow-up like "now add tests for that" works.
Examples
ycode> Add dark mode to the settings page
ycode> Why does `npm run build` fail? Fix it.
ycode> Write unit tests for src/utils/date.ts and make sure they pass
ycode> Rename the `User.fullname` field to `full_name` everywhere
ycode> Explain how requests are authenticated in this project
ycode> Commit these changes with a good message # git commit asks for approval
Security model
YCode gives a language model the ability to edit files and run commands, so it treats both as risky.
Command classification (ycode/security/permissions.py). Every command line is split into segments (&&, ||, ;, |), and command substitutions ($(...) and backticks) and bash -c "..." strings are classified recursively. The most severe result wins.
| Level | Examples | Behavior |
|---|---|---|
| SAFE | npm test, pytest, git status, ls, cargo build |
Runs immediately |
| REQUIRES_APPROVAL | rm, mv, sudo, chmod, chown, kill, git push, git reset --hard, git clean, git commit, git checkout -- ., npm publish, curl β¦ | sh, find -delete, writes redirected outside the project, reading .env/key files |
Shows β YCode wants to run: β¦ Allow? [y/N/a] |
| BLOCKED | rm -rf /, rm -rf ~, fork bombs, mkfs, dd of=/dev/β¦, shutdown, writes to raw devices |
Never runs, even with --yes |
At the approval prompt, y allows the command once and a allows that exact command for the rest of the session. Anything else denies it, and the model is told not to retry.
Approval modes:
normal(default): SAFE commands run, risky commands ask, blocked commands are refused.strict: also asks before every file write and every command that isn't read-only.auto: risky commands run without asking. Blocked commands are still refused.
Filesystem confinement. Every path is resolved, symlinks included, and has to stay inside the project directory. ../, absolute paths and symlinks that point outside the project are rejected. Writes into .git/ are always rejected. Reading files that look like secrets (.env*, *.pem, id_rsa, ...) asks first. allow_outside_workspace = true in your global config lifts the confinement.
Untrusted repositories. A project's .ycode/config.toml can only make settings stricter. It cannot switch on auto approvals or access outside the workspace, so cloning a repository can't silently loosen your safety settings.
Git. YCode never commits or pushes on its own. Those commands always need your approval.
Limits. This is a guardrail, not a sandbox. When the agent runs code it wrote (python script.py, npm test), that code can do anything your user account can. For untrusted code, run YCode inside a container or VM.
Configuration
Settings are resolved in this order, with later sources winning:
- Built-in defaults
- Global config:
~/.ycode/config.toml(move this directory withYCODE_HOME) - Project config:
<project>/.ycode/config.toml(can only tighten security settings) - Environment:
YCODE_PROVIDER,YCODE_LOCAL_MODEL,YCODE_MODELS_DIR,YCODE_MODEL,YCODE_MAX_STEPS,YCODE_MAX_TOKENS,YCODE_EFFORT,YCODE_APPROVAL_MODE,YCODE_THEME,YCODE_COMMAND_TIMEOUT,YCODE_IGNORE_DIRS - Command-line flags
# ~/.ycode/config.toml
provider = "local" # local (default: YCode's own model, no key) | anthropic (Claude)
local_model = "v5" # v2 | v3 | v4 | v5 | a model directory (default: v5, or v4 when memory is short)
model = "claude-opus-5-5" # any Claude model ID (provider = "anthropic")
max_steps = 50 # model calls per task before YCode stops
max_tokens = 64000 # output token cap per model call
effort = "high" # low | medium | high | xhigh | max (models that support it)
approval_mode = "normal" # strict | normal | auto
theme = "default" # default | mono (no colors)
command_timeout = 120 # seconds, per command
max_output_chars = 30000 # command/tool output sent back to the model
refusal_fallback = true # retry declined requests on Anthropic's recommended fallback model
# ignore_dirs = [...] # replaces the default ignore list
extra_ignore_dirs = ["generated", "vendor"] # adds to it
The default model is claude-opus-5-5. You can set any model ID, for example claude-sonnet-5-5, claude-fable-5-1, claude-haiku-4-5 or claude-sonnet-4-5. YCode adapts the request to the model. It turns on adaptive thinking and effort only on models that support them, and server-side refusal fallbacks only on Claude Fable 5.1, Opus 5.5, Opus 5 and Sonnet 5.5. If you route through a gateway with ANTHROPIC_BASE_URL, YCode sends a plainer request shape.
By default these directories are ignored: node_modules .git dist build .next .nuxt .cache venv .venv env __pycache__ .pytest_cache .mypy_cache .ruff_cache target coverage .gradle .idea .dart_tool .tox .eggs.
YCODE.md instructions
Put a YCODE.md at the root of your repository (or at .ycode/YCODE.md) and YCode adds it to the agent's instructions for every task in that project:
# YCode Project Instructions
Use TypeScript.
Run npm test before finishing.
Do not modify generated files.
Use functional React components.
The banner and /status show when instructions are loaded. Files longer than 20,000 characters are truncated.
Development
pip install -e ".[dev]"
python -m pytest
Set YCODE_DEBUG=1 to see full tracebacks for unexpected internal errors. Normal user errors are always shown as short messages, never as tracebacks.
Some guidelines:
- Keep the agent free of UI and provider imports. Communicate through
AgentEventsandLLMProvider. - Tools return a
ToolResultand never raise for expected failures. The registry turns exceptions into error results the model can react to. - New command patterns belong in
security/permissions.py, with tests intests/test_security.py.
Testing
The test suite needs no API key and makes no network calls:
tests/test_anthropic_provider.pymocks the Anthropic client: request shape, stream parsing, error mapping and missing credentials.tests/test_anthropic_wire.pyruns the realanthropicSDK against a mock HTTP transport that returns canned server-sent events. It checks the exact JSON YCode sends across a full tool-use round trip.tests/test_lm.pycovers YCode-LM: tokenizer round-trips (including Unicode), special tokens, a KV-cache check against full recomputation, answer-only loss masking, dataset preparation, pretraining that measurably lowers loss, SFT, resume, checkpoint round trips and theycode-lmCLI end to end. These tests are skipped if PyTorch isn't installed.tests/test_local_provider.pychecks the local provider: no API key, no tools sent,--localfrom the CLI, and how bundled models are found.tests/test_assist.pychecks answering without an API: documentation lookups and checked function writing.tests/test_agent_loop.pydrives the agent with a scripted fake provider: multi-step tasks, parallel tool calls, the step limit, interruption, truncated tool calls and refusals.- The other test files cover configuration, the banner, file tools, path security, command classification and approvals, command execution (timeouts, exit codes, secret stripping), git, project detection and YCODE.md, slash commands, and the CLI and REPL.
python -m pytest -q
Roadmap
- YCode-LM: tool-calling training data, so the local model can drive the agent
- YCode-LM: train v5 much longer on GPUs (
ycode-lm autotrain,--shardare ready), then publish it on Hugging Face - YCode-LM: faster CPU inference for v5 (8-bit weights)
- More providers: OpenAI-compatible, local models through Ollama
- Session persistence and resume (
ycode --continue) - Context compaction for very long sessions
- Optional sandboxed command execution (containers)
/undothat restores files to the state before the last task- MCP server support for extra tools
- A richer TUI mode (Textual) as an optional front-end