AI News HubLIVE
In-site rewrite6 min read

Show HN: Symbio self fine-tuning AI loop

Symbio is a local AI agent that learns from your corrections and fine-tunes itself via LoRA. It features a Mixture of Agents mode, on-the-fly skill learning, automatic mistake capture, and local-only data storage.

SourceHacker News AIAuthor: huyedit

Notifications You must be signed in to change notification settings

Fork 1

Star 19

BranchesTags

Open more actions menu

Folders and files

NameName

Last commit message

Last commit date

Latest commit

History

107 Commits

107 Commits

docs

docs

spaces/symbio_demo

spaces/symbio_demo

symbio

symbio

symbio_native

symbio_native

tests

tests

tests_mcp

tests_mcp

.env.example

.env.example

.gitignore

.gitignore

CODE_OF_CONDUCT.md

CODE_OF_CONDUCT.md

CONTRIBUTING.md

CONTRIBUTING.md

LICENSE

LICENSE

NOTICE

NOTICE

PLAN.md

PLAN.md

README.md

README.md

benchmark_7b_class.json

benchmark_7b_class.json

benchmark_mlx.json

benchmark_mlx.json

benchmark_mlx_more.json

benchmark_mlx_more.json

benchmark_more_models.json

benchmark_more_models.json

benchmark_qwen25_9b.json

benchmark_qwen25_9b.json

benchmark_qwen_coder.json

benchmark_qwen_coder.json

computer.py

computer.py

config.example.json

config.example.json

conftest.py

conftest.py

debug_response.py

debug_response.py

dollar_tree_apple_sider_bacon.md

dollar_tree_apple_sider_bacon.md

golden_cases.json.example

golden_cases.json.example

install.sh

install.sh

main.py

main.py

memory.db

memory.db

memory_monitor.py

memory_monitor.py

models.json

models.json

planner.py

planner.py

pyproject.toml

pyproject.toml

rag.py

rag.py

raw_generate.py

raw_generate.py

requirements.txt

requirements.txt

seed_training.py

seed_training.py

setup.sh

setup.sh

smoke_test.py

smoke_test.py

stress_chat.py

stress_chat.py

switch_model.py

switch_model.py

symb

symb

test_adapter_idle.py

test_adapter_idle.py

test_auto_learn_e2e.py

test_auto_learn_e2e.py

test_chat_stress.py

test_chat_stress.py

test_cli.py

test_cli.py

test_computer.py

test_computer.py

test_deferred_learn.py

test_deferred_learn.py

test_dispatch.py

test_dispatch.py

test_dynamic_names.py

test_dynamic_names.py

test_eval.py

test_eval.py

test_file_tools.py

test_file_tools.py

test_golden.py

test_golden.py

test_golden_extensible.py

test_golden_extensible.py

test_health.py

test_health.py

test_learn.py

test_learn.py

test_learn_e2e.py

test_learn_e2e.py

test_main_loop.py

test_main_loop.py

test_mcp_tools.py

test_mcp_tools.py

test_rag.py

test_rag.py

test_safety.py

test_safety.py

test_sandbox_remote.py

test_sandbox_remote.py

test_setup.py

test_setup.py

test_skill_adapters.py

test_skill_adapters.py

test_streaming.py

test_streaming.py

test_telegram.py

test_telegram.py

test_threshold_training.py

test_threshold_training.py

test_utils.py

test_utils.py

Repository files navigation

Local Ai that learns from your corrections. No Cloud, No subscriptions.

Symbio takes notes and can construct it into training data to fine-tune itself - so you can stop repeating yourself.

| GitHub | Try it now

Symbio develops as you tell it what to do in repeat.

Try the interactive demo — the agent's real tag parser, self-correction miner, research memory, and RAG retriever running in your browser: https://huggingface.co/spaces/HuyEdits/symbio-demo

MOA feature

Symbio has a MOA (Mixture of Agents) mode. Instead of fine-tuning one big model for every task, the headmaster delegates bounded sub-tasks to smaller worker models via tool calls. The worker executes, and if it fails it returns to the headmaster for guidance. Once it works, a note is saved for both sides. If the same mistake repeats past the configured threshold, both the worker and the headmaster are fine-tuned: the worker learns how to execute the task, and the headmaster learns how to delegate it more efficiently.

Skill feature

Symbio can learn skills on the fly. A skill starts as a simple markdown note with step-by-step instructions. As errors and corrections accumulate, they are logged in a hidden .md.health.jsonl sidecar so the note itself stays clean and readable. Once the mistake threshold is reached, the collected examples are fed into a LoRA fine-tune that creates a dedicated worker adapter for that skill — one adapter = one skill. Adapters are hot-swappable and can be archived if unused.

Use /new-skill or symb skill new to create one, /skill-adapters to list them, and /archive / /restore to manage idle notes and adapters.

What it does

Chat through a local CLI or a Telegram bot.

Save facts and notes as markdown files in notes/.

Read, write, search, and patch files inside the project directory.

Run sandboxed shell commands and short Python snippets.

Check email via IMAP/SMTP (when configured).

Digest notes into training data and fine-tune a LoRA adapter on the fly.

Persist every conversation turn to JSONL and an SQLite store.

Please star this project too. It would help me out SO SO much. :3 # Print one value, e.g. agent.temperature symb config set symb train # Run LoRA training symb skill list # List saved skills and their adapter status symb skill new # Create a new skill (interactive steps) symb skill rm # Delete a skill, adapter, and training data symb archive # Run auto-archive for idle notes/adapters symb archive --dry-run # Preview what would be archived symb archive --restore note|adapter symb gateway status # Check Telegram gateway readiness symb gateway start # Start the Telegram bot symb gateway stop # Stop a running gateway

Legacy python main.py flags still work:

python main.py --telegram python main.py --train

Telegram bot

Run Symbio as a Telegram bot so you can chat from your phone:

symb gateway start

Legacy equivalent: python main.py --telegram

Check gateway readiness first:

symb gateway status

On first run you will be prompted for a bot token from @BotFather. The token is saved to config.json. For better security, set the environment variable SYMBIO_TELEGRAM_TOKEN instead; it overrides the config file.

You must add your Telegram chat ID to telegram.allowed_chat_ids:

symb config set telegram.allowed_chat_ids '[123456789]'

Send any message to the bot, then copy the chat ID from the refusal message if you haven't set it yet.

Dangerous actions from Telegram — blocked shell commands, new browser domains, Python code, config changes, cron jobs, digest, and training — ask for approval via an inline keyboard before running.

Telegram slash commands

Command Description

/start Welcome message

/help List available commands

/ping Last turn latency breakdown

/status Model, adapter, data, and last turn timings

/golden Run golden-set regression check

/train Start LoRA training

/selfcheck Verify enabled features and auto-fix safe issues

/setup How to change configuration

/tools Toggle tool groups

/cancel Clear the current session

Slash commands

Command Description

/quit Exit the chat

/save Save the current conversation to training data

/train Run LoRA fine-tuning and reload the adapter

/learn Manually learn from your last correction (auto-learn is on by default)

/digest Convert notes into training samples

/note [title] Create a markdown note

/notes List saved notes

/new-skill Create a skill note and start training a worker adapter

/skills List saved skill notes

/skill-adapters List skill adapters and their training/idle status

/archive Archive idle notes/adapters (or preview with --dry-run)

`/restore note adapter `

/status Show model, adapter, notes, and session info

/selfcheck Verify enabled features and auto-fix safe issues

/setup Re-run the setup wizard (names, model, features)

/compact Compress memory/profile store and archive the original

/model List model presets

/model Switch to a named model preset (restart to load)

/run Run a sandboxed shell command

/forget_last Remove the last exchange from history

/prune Remove stale adapter checkpoints

Learning from corrections

Symbio detects natural corrections automatically and turns them into training data without you typing /learn. Instead of training on every single correction, it saves each mistake as a markdown note in notes/mistakes/ and only fine-tunes once enough notes have accumulated.

Typical flow:

You: What is my name? Symbio: Your name is Bob. You: No, I'm Alice. Symbio: Your name is Alice. [System] Correction detected (correction phrase). Saved mistake note: 20260715_123456_What_is_my_name.md 1/5 mistake note(s) collected. Training will run after 4 more correction(s).

Symbio will:

Detect correction phrases ("No, ...", "Actually ...", "That's wrong", etc.) or an exact repeat of your last question.

Extract the original question, the wrong answer, the user's correction, and the corrected answer.

Save them as a markdown note in notes/mistakes/.

When learn.mistake_threshold (default 5) notes have accumulated, digest them into training_data/train.jsonl and run a short LoRA update (learn.batch_train_iters, default 25).

Archive the used mistake notes to notes/mistakes/archive/ and reload the adapter.

The /learn command is still available to force a mistake note from the last correction, but it is no longer required.

Learning from its own tool mistakes

The same mistake-note pipeline also captures a second, fully automatic pattern that needs no user involvement at all: a tool call that fails, immediately followed by one that works. This is exactly the "wrong command, try the right one" pattern already hand-seeded into every install's base training data —

You: Open Chrome. Symbio: chrome [Tool: run_command] [Observation] Command 'chrome' exited error. Output: Command not found: chrome Symbio: 'chrome' isn't a command here — trying the native way. open -a 'Google Chrome' [Learn] Tool mistake captured: 20260721_213045_System_observation_Command_chrome.md

— except now it's learned from real usage, not just the seed examples. It feeds into the exact same notes/mistakes/ → threshold → digest → guarded-training pipeline as conversational corrections above, so both count toward the same learn.mistake_threshold. Nothing is saved if the model keeps failing without ever finding a working alternative within the turn — only a confirmed fix gets captured.

Tune the behaviour in config.json:

Key Default Note

learn.enabled true Enable correction learning

learn.auto true Detect corrections automatically

learn.auto_train true Run the fine-tune automatically when the threshold is reached

learn.mistake_threshold 5 Number of mistake notes before a batch fine-tune runs

learn.batch_train_iters 25 LoRA iterations for the threshold-triggered batch update

learn.boost_factor 3 Copies of each correction sample written per mistake note

learn.correction_phrases [...] Phrases that trigger correction detection

Fine-tuning details

Symbio uses LoRA (Low-Rank Adaptation) via Apple's MLX-LM framework. The base model weights stay frozen; only small adapter matrices are trained on curated conversation, notes, and corrections. Training is invoked through the official mlx_lm lora CLI:

symb train # full pass using lora.iters

The resulting adapter is saved to adapters/ and loaded automatically on the next start.

Setting Default What it controls

lora.rank 8 Width of the low-rank matrices

lora.num_layers 8 How many transformer layers get adapters

lora.scale 5.0 Adapter output scaling

lora.dropout 0.1 Dropout for regularization

lora.learning_rate 1e-4 Training step size

lora.iters 50 Iterations for /train

lora.max_seq_length 2048 Training context length

lora.save_every 50 Checkpoint frequency

Golden set: catching a fine-tune that silently breaks things

Every LoRA update (/train, the train_adapter tool, the auto-training that follows enough corrections, or the end-of-session prompt) is checked against a small, fixed go

[truncated for AI cost control]