Skip to content

cutecycle/yggdra

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

237 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🌳 yggdra

⚠️ EARLY STAGE SOFTWARE β€” NOT PRODUCTION READY

Yggdra is an experimental, rapidly evolving project. Interfaces are unstable and may change dramatically without notice. Features, APIs, CLI flags, and behavior are subject to breaking changes between releases. Use at your own risk, especially with important or sensitive files.


Yggdra is an airgapped agentic TUI β€” a Rust app that connects to Ollama, gives your model a toolbox (ripgrep, git, python, file editing, even nested sub-agents), and lets it operate on your filesystem. No cloud. No API keys. No phoning home. Just you, a terminal, and a local model.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ yggdra ─────────────────────────────────┐
β”‚ 🌷 session a1b2c3  Β·  qwen3:8b  Β·  build mode  Β·  3 tasks remaining  β”‚
│─────────────────────────────────────────────────────────────────────────│
β”‚ user: find all the TODO comments and summarize them                     β”‚
β”‚ assistant: on it β€” searching with rg first…                             β”‚
β”‚ [TOOL_OUTPUT: rg = src/ui.rs:42: // TODO: dark mode toggle]            β”‚
β”‚ assistant: found 7 TODOs across 4 files. here's the summary…           β”‚
│─────────────────────────────────────────────────────────────────────────│
β”‚ >                                                                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

~6k lines of Rust Β· 4.8 MB binary Β· <50 MB RAM Β· zero network dependencies

Optimized for small language models β€” tested against sub-2B models from Qwen, Llama, Gemma, SmolLM, and DeepSeek. If it works on qwen3.5:0.8b, it works.


⚠️ Disclaimers

  • Alpha/Beta Stage: Yggdra is under active development. Expect breaking changes, missing features, and rough edges.
  • Unstable Interfaces: CLI arguments, configuration formats, data structures, and behavior may change without deprecation warnings.
  • Experimental Features: Features like thinking block display, sub-agents, and persistence mechanisms are prototype-grade.
  • Use at Your Own Risk: This tool gives an AI direct access to your filesystem. Always review what the agent is about to do before executing in non-Plan mode. Back up your data.
  • No Backwards Compatibility Guarantees: Session formats, config files, and stored data may become incompatible with future releases.

If you need stability, mature tooling, or production guarantees, consider cloud-based alternatives. Yggdra is for explorers and people who value local-first automation over stability.


Why?

Most agentic coding tools need the cloud. Yggdra doesn't. It's built for the scenario where you can't β€” or won't β€” send your code to someone else's servers. Plug in an Ollama instance (local or on your tailnet), point it at a project, and let it work. The TUI is clean, sessions persist, and the model can spawn sub-agents to parallelize work.


Quick start

You need: Ollama running somewhere reachable, and Rust 1.70+ to build.

git clone https://github.com/cutecycle/yggdra.git
cd yggdra
cargo build --release
./target/release/yggdra          # or: make install β†’ ~/.local/bin/yggdra

First run? Pull a model and go:

ollama pull qwen3:8b             # or whatever you like
yggdra                           # that's it

Four modes

Flag Mode What it does
--ask Ask Read-only. Answers questions, no autonomous actions, can't touch your files.
--plan Plan (default) Interactive. Agent proposes; you drive.
--build Build Autonomous. Agent kicks itself to keep working until you stop it.
--one One Like Build, but stops with an OS notification when the task is complete ([DONE] or no tool calls in a turn).

Mode persists across sessions (saved to ~/.yggdra/config.json or .yggdra/config.json), so you only set it once. Cycle in-app: Plan β†’ Build β†’ One β†’ Ask.


The toolbox

Available tools (all local, no network):

Tool What it does
rg Ripgrep search across files
exec Run local commands (PATH-resolved, no network binaries)
shell Run a shell command (sh -c wrapper)
setfile Write entire file β€” creates if missing, git-tracked
patchfile Line-range replacement (targeted patch without full-file overwrite)
commit Stage and commit with git
python Execute Python snippets
ruste Compile and run Rust snippets
spawn Spawn a child sub-agent (up to 10 levels deep)

Tool calls default to JSON (OpenWebUI-style). Legacy <|tool>…<|end_tool> and [TOOL: …] formats are still parsed for backward compatibility.

Results come back as [TOOL_OUTPUT: name = ...] and the model keeps going.

Sub-agents

The model can spawn child agents to handle subtasks in parallel β€” up to 10 levels deep. Each sub-agent gets the same tools (minus the ability to spawn further agents, to prevent infinite recursion).


Sessions & storage

Every directory gets its own session. Walk into a project, launch yggdra, and your conversation is right where you left it.

.yggdra_session_id               ← marker file (add to .gitignore)

~/.yggdra/
└── sessions/<uuid>/
    β”œβ”€β”€ messages.db               ← SQLite β€” fast, transactional
    └── metadata.json             ← model, timestamps, etc.

Open two terminals in the same project? Both instances share the same SQLite DB and sync via polling β€” you'll see messages appear in both windows.


The knowledge base

Symlink .yggdra/knowledge to any local docs folder and the model can search it with rg β€” no indexing server, no vector DB.

ln -s ~/my-docs .yggdra/knowledge

The model treats it like any other directory. Point it at API references, textbooks, man pages, whatever you've got locally.


Knowledge gaps

After every response, yggdra quietly asks the model: "what did you wish you knew?" The answers get logged to .yggdra/gaps. Over time, you build a map of what your local model struggles with β€” handy for knowing what to add to your knowledge base.


Configuration

Variable Default What it does
OLLAMA_ENDPOINT http://localhost:11434 Where your Ollama lives
OLLAMA_MODEL auto-detect Which model to use

Config files (~/.yggdra/config.json for global, .yggdra/config.json for per-project) override env vars and persist mode/model/endpoint between runs. Both are watched live β€” edit and the running TUI picks it up.

export OLLAMA_ENDPOINT=http://10.0.0.5:11434   # tailnet box
export OLLAMA_MODEL=qwen3:8b
yggdra --build

Global agent instructions

Create ~/AGENTS.md to define your personal preferences, persona, or constraints that apply across every project:

# My global instructions

- Prefer short, direct answers
- Always write tests for Rust code
- My name is Nina β€” address me by name

When yggdra starts, it reads ~/AGENTS.md first, then appends the project-local AGENTS.md (if any) after a # --- project AGENTS.md --- separator. Both files are watched live β€” edits are picked up without restart.

OpenAI-compatible endpoints (OpenRouter, etc.)

Yggdra speaks Ollama's API by default and also supports the OpenAI chat completions API via the async-openai library (with SSE streaming). Point endpoint in ~/.yggdra/config.json at any OpenAI-compatible server β€” OpenRouter, a local proxy, or anything that speaks /v1/chat/completions. Useful for hosted models when you're not strictly airgapped.


Slash commands

  • /help, /models, /quit
  • /one β€” switch to One mode for a single autonomous task
  • /abort β€” kill stuck streams, async tasks, and in-flight tool execution
  • /shell CMD β€” run a shell command inline without going through the agent
  • /test_notification β€” fire a test OS notification to verify your setup

macOS notifications

yggdra uses osascript for native notifications (notify-rust silently fails on unbundled CLIs). To allow them:

  1. System Settings β†’ Notifications β†’ Script Editor
  2. Enable Allow Notifications

Run /test_notification inside yggdra to confirm.


Nice touches

  • Native notifications β€” OS notifications on new session and model response.
  • Adaptive theming β€” detects light/dark terminal and picks colors accordingly. Solarized-inspired palette.
  • Structured logging β€” every message written to .yggdra/log/YYYY/MM/DD/HHMM/SS-role.md for full auditability.
  • Task tracking β€” built-in SQLite-backed task graph with checkpoints and dependency tracking. The model manages its own todo list.
  • Steering directives β€” inject system-level constraints (be concise, output JSON, etc.) that get prepended to every prompt.

Building & testing

cargo build --release            # optimized binary (LTO, stripped)
cargo test --lib                 # 450 tests β€” keep them green
make install                     # copy to ~/.local/bin/

The test suite includes terminal integrity tests (ratatui TestBackend for cell-level garbage detection), rendering pipeline tests, and the model gauntlet. See CONTRIBUTING.md for the full dev guide and ARCHITECTURE.md for the deep dive.


Model gauntlet

src/bin/test_models.rs runs 26 capability tests per model β€” XML tool calls, discipline (no preamble, no hallucination, no code fences), multi-call, thinking, and humor/personality.

The default model set covers mainline OSS models ≀2B parameters, one from each major provider:

Provider Model Params Released
Alibaba / Qwen qwen3.5:0.8b-bf16 873M May 2026
Alibaba / Qwen qwen2.5:1.5b 1.5B Sep 2024
Alibaba / Qwen qwen3.5:2b-q4_K_M 2.3B May 2026
Meta llama3.2:1b 1.24B Sep 2024
Google gemma3:1b 1B Mar 2025
HuggingFace smollm2:1.7b 1.7B Nov 2024
DeepSeek deepseek-r1:1.5b 1.5B Jan 2025

Run it with:

./target/release/test_models http://localhost:11434        # all default models
./target/release/test_models http://host:11434 model:tag  # specific model

Results below are updated by the gauntlet itself after each run:

Model Params Quant Score
qwen3.5:2b-q4_K_M 2.3B Q4_K_M 19/26 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘
gemma:2b 3B Q4_0 3/26 β–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘
qwen3.5:4b-q4_K_M 4.7B Q4_K_M 21/26 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘
gemma4:latest 8.0B Q4_K_M 20/26 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘
qwen3.5:9b-q4_K_M 9.7B Q4_K_M 21/26 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘

Vendored dependencies

All crates are committed to vendor/ via cargo vendor. Building requires zero network access β€” cargo build --release resolves everything locally.

  • Offline by design: perfect for air-gapped machines; no crates.io reach required at build time.
  • Reproducible: the exact dependency tree is in the repo β€” no registry surprises, no yanked crates, no Cargo.lock drift between machines.
  • CI-friendly: pipelines without internet access build cleanly.

This is wired up in .cargo/config.toml:

[source.crates-io]
replace-with = "vendored-sources"

[source.vendored-sources]
directory = "vendor"

To update a dependency: run cargo update then cargo vendor and commit the changes to vendor/.


Troubleshooting

"Ollama is offline" β€” Start it (ollama serve) or point OLLAMA_ENDPOINT at the right address.

"Model not found" β€” ollama pull <model> or type /models inside yggdra to see what's available.

Slow responses β€” That's your GPU talking, not yggdra. Try a smaller model or check ollama ps.

Session weirdness β€” Delete .yggdra_session_id in the project dir to start fresh.


License

MIT

About

the little agent cli that could

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages