Tythan Code: a terminal AI coding assistant that chats with any model (Anthropic, OpenAI-compatible, local), reads/edits files, searches the project and runs commands — with your confirmation.
Project description
Tythan Code
The AI coding agent that won't ship vulnerabilities.
A Cursor-style AI coding assistant that lives in your terminal — with any model you want and a built-in security auditor. Chat about your project; the assistant reads and edits files, searches the codebase, runs shell commands, and scans its own output for security issues before calling a task done. Every file change is shown as a diff and every command waits for your confirmation.
_ _ _ _
| |_ _ _| |_| |_ __ _ _ _ __ ___ __| |___
| _| || | _| ' \/ _` | ' \ / _/ _ \/ _` / -_)
\__|\_, |\__|_||_\__,_|_||_| \__\___/\__,_\___|
|__/
Features
- Security-first agent — the
security_scantool detects leaked secrets and API keys (AWS, GitHub, Stripe, Google, Slack, Telegram, JWTs, Bearer tokens + a Shannon-entropy detector for everything else), dangerous code patterns (eval, pickle, SQL built from f-strings,shell=True,verify=False, weak ciphers,randomused for secrets, ...) and insecure config (wildcard CORS, JWTnone, debug mode, plain-http endpoints). The agent audits code it just wrote and fixes CRITICAL/HIGH findings before declaring a task done; run/auditany time for an instant offline report. - Dependency CVE check (SCA) — pinned dependencies from
requirements.txt,pyproject.tomlandpackage.jsonare checked against the OSV.dev vulnerability database (free, no key). Included in/audit; the agent can request it viasecurity_scan(include_dependencies=true). Degrades gracefully offline. - Any model — native Anthropic API plus any OpenAI-compatible endpoint:
OpenAI, OpenRouter, Groq, DeepSeek, Mistral, xAI, and fully local models via
Ollama / LM Studio / vLLM. Switch providers mid-session with
/provider. - Agentic loop — the model reads files, edits them, runs tests and iterates until the task is done, streaming its answer live.
- Human in the loop, per hunk — a new file gets a single whole-file diff
and
[y/N]; a change to an existing file is split into independent hunks (git add -pstyle) so you can accept some and reject others in one response instead of an all-or-nothing yes/no —y/nper hunk,ato accept it and everything remaining,dto reject it and everything remaining. Only the accepted hunks are written; the tool result tells the model how many of the total were actually applied. Shell commands still ask a plain yes/no before running.--yoloturns all of this off. @filementions — type@src/app.pyin your message to attach that file's contents.- Workspace-confined — all file operations are locked inside the project directory; path traversal is rejected.
.gitignore-aware —list_files,search,code_search,/auditand the dependency check all skip whatever the project's own.gitignoreexcludes, on top of the usual junk directories (.git,node_modules, ...). No more noise from build output or vendored code that happens to live outside those hardcoded names.- Project rules — drop a
.tythancode/rules.md,.tythancoderules,AGENTS.mdor.cursorrulesfile (checked in that order, first one found wins) in the workspace root and Tythan Code loads it into every system prompt automatically: conventions, build/test commands, things it should never touch. No more repeating the same context every session; the banner tells you when one was picked up. - Task plan tracking — for multi-step work the assistant maintains a
visible todo list (
todo_write), shown as a checklist as it works through each step. Check it any time with/todos. - Ranked codebase search (
code_search) — BM25 keyword ranking over chunked files, for when you don't know the exact string to grep for ("where is retry logic for HTTP calls?"). This is lexical ranking, not embeddings — fully offline, no model call, no vector database — but it recovers a lot of what naive grep misses, including matchingread_file/readFilefrom a query like "read file". Built lazily on first use, then cached on disk under~/.tythancode/index/keyed by each file's modification time and size, so re-opening the same project later only re-tokenizes what actually changed instead of the whole codebase again./reindexforces an eager rebuild (still fast, for the same reason). - MCP client — connect any Model Context Protocol
stdio server (filesystem, fetch, databases, your own internal tools, ...)
by adding it under
"mcp_servers"in~/.tythancode/config.json. Their tools show up to the model asmcp__<server>__<tool>alongside the built-ins. Tythan Code doesn't control what a third-party server's tool actually does, so every call is confirmed before running — unless the server itself marks the toolreadOnlyHint, the same wayread_fileneeds no confirmation./mcpshows what's connected; a server that fails to start is reported and simply contributes no tools rather than blocking startup. - Web fetch (
fetch_url) — read documentation, changelogs or an API response straight into the conversation, the terminal equivalent of Cursor's@web. Confirmed before running, same asrun_command, and every request — plus every individual redirect hop — is resolved and checked against private/loopback/link-local/reserved address ranges before connecting, so a prompt-injected "fetch http://169.254.169.254/..." can't be used to reach cloud metadata endpoints or internal services. - Tools —
read_file,write_file,edit_file(exact string replace),list_files(glob),search(regex),code_search(ranked),todo_write,fetch_url,run_command, plus whatever connected MCP servers add. - Undo (
/undo) — everywrite_file/edit_fileis checkpointed before it runs./undoreverts the whole last turn's file changes in one step, survives restarting Tythan Code, and stays out of the way otherwise: nothing is written to~/.tythancodeuntil a file actually changes. Shell commands run viarun_commandaren't covered — there's no honest way to snapshot and revert arbitrary shell effects, so this is a safety net for agent-authored edits, not a full undo of everything the agent does. Files over 5MB or that aren't valid UTF-8 are skipped rather than checkpointed (so/undonever "restores" a lossy, corrupted copy) — Tythan Code tells you when this happens./checkpoints [n]lists recent checkpoints (10 by default, up to the 50 retained per workspace). - Automatic context compaction — long sessions don't hit a hard
context-length error. When the conversation approaches the model's context
window, Tythan Code summarizes the older turns into one message and keeps
the most recent turns verbatim, so the assistant keeps working instead of
failing outright. Trigger it manually with
/compact, check usage with/context.
Install
cd tythan-code
pip install .
Requires Python 3.10+. For the default Anthropic provider:
export ANTHROPIC_API_KEY=sk-ant-...
# or: ant auth login (the SDK picks the profile up automatically)
Providers
On first run Tythan Code creates ~/.tythancode/config.json:
{
"default_provider": "anthropic",
"providers": {
"anthropic": {"type": "anthropic", "model": "claude-opus-4-8"},
"openai": {"type": "openai", "base_url": "https://api.openai.com/v1",
"api_key_env": "OPENAI_API_KEY", "model": "gpt-4o"},
"openrouter": {"type": "openai", "base_url": "https://openrouter.ai/api/v1",
"api_key_env": "OPENROUTER_API_KEY", "model": "anthropic/claude-sonnet-4.5"},
"ollama": {"type": "openai", "base_url": "http://localhost:11434/v1",
"model": "qwen2.5-coder:14b"}
}
}
Add any OpenAI-compatible service as a new entry (type: "openai" +
base_url + api_key_env + model). Local endpoints (localhost) don't need
a key. type: "anthropic" uses the native Anthropic API with adaptive
thinking, effort control and prompt caching.
Each provider entry can also set "context_window": <tokens> to override how
much context Tythan Code assumes that model has before it proactively
compacts history. Without it, Tythan Code guesses conservatively: 200k for
Anthropic, 128k for known hosted APIs (OpenAI, OpenRouter, Groq, ...), and a
cautious 8k for anything on localhost — local model servers commonly run with
a much smaller context than the underlying model supports unless configured
otherwise, so set this explicitly if you've raised num_ctx (Ollama) or
similar.
MCP servers
Add stdio MCP servers under "mcp_servers" in the same config file:
{
"mcp_servers": {
"fetch": {"command": "uvx", "args": ["mcp-server-fetch"]},
"filesystem": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allow"]}
}
}
command/args launch the server as a subprocess over stdio (the same
transport npx/uvx-based servers use); env (optional) adds extra
environment variables on top of a safe inherited default (PATH, HOME,
...) — it does not replace the environment outright. Tythan Code connects to
every configured server at startup; a server that fails to start is reported
once and simply has no tools, it doesn't stop Tythan Code from working.
Usage
tythancode ~/my-project # interactive chat in that workspace
tythancode # current directory
tythancode -p "fix the failing test" # one-shot, non-interactive
tythancode --provider ollama # pick a provider for this session
tythancode --model claude-sonnet-5 --effort xhigh
tythancode --yolo # auto-approve everything (careful!)
tythancode --no-checkpoints # don't record file checkpoints (disables /undo)
In-chat commands
| Command | Effect |
|---|---|
/help |
show help |
/clear |
reset the conversation |
/provider [name] |
list providers / switch (resets the chat) |
/model <id> |
switch model within the current provider (context window stays as configured for the provider — see /context) |
/effort <lvl> |
low / medium / high / xhigh / max (Anthropic) |
/audit [path] |
offline security scan of the workspace (or a subpath) |
/yolo |
toggle confirmation prompts |
/undo |
revert the file changes from the last turn |
/checkpoints [n] |
list recent undo checkpoints (10 by default) |
/todos |
show the assistant's current task plan |
/reindex |
rebuild the code_search index now (otherwise built lazily on first use) |
/mcp |
show connected MCP servers and the tools they expose |
/compact |
summarize older history now to free up context |
/context |
show estimated context usage vs. the model's window |
/exit or Ctrl+D |
quit |
Example session
you> add a --verbose flag to @cli.py
assistant
⚙ read_file {"path": "cli.py"}
⚙ edit_file {"path": "cli.py", "old_string": "...", "new_string": "..."}
╭─ cli.py — hunk 1/1 ───────────────────────────╮
│ @@ -12,1 +12,1 @@ │
│ - parser.add_argument("--quiet", ...) │
│ + parser.add_argument("--verbose", ...) │
╰────────────────────────────────────────────────╯
apply this hunk? [y/n/a/d/?] y
Done — added the flag and wired it to the logger setup.
tokens: 8231 in / 412 out / 7100 cached
Development
pip install -e ".[dev]"
pytest # tools, agent loop and provider tests run offline
Releasing to PyPI
The package builds and installs cleanly today (python -m build && twine check dist/* both pass, and the built wheel installs into a clean venv with
a working tythancode command) — what's left is account setup, not code:
- Fill in
authorsand[project.urls]inpyproject.toml— left out on purpose rather than guessed, since they'd otherwise ship placeholder name/repo info to the public index permanently. - Register the project on PyPI (the name
tythan-codeis free as of this writing) and configure a trusted publisher for this repo pointing at.github/workflows/publish.yml— no API token to generate or store as a secret. - Cut a GitHub Release;
publish.ymlbuilds and uploads automatically.ci.ymlruns the test suite on every push/PR across Python 3.10–3.13.
To build and sanity-check locally without publishing:
pip install build twine
python -m build
twine check dist/*
Architecture
tythancode/
├── cli.py # REPL, slash commands, @mentions
├── agent.py # provider-agnostic agent loop + confirmations
├── tools.py # tool schemas + sandboxed executors
├── ui.py # rich rendering: streams, diffs, prompts
├── security.py # offline security scanner (/audit + agent tool)
├── sca.py # dependency CVE check via OSV.dev
├── config.py # ~/.tythancode/config.json provider registry
├── compaction.py # round-splitting + token-estimate helpers for /compact
├── checkpoints.py # file-level undo store behind /undo, /checkpoints
├── storage.py # shared ~/.tythancode per-workspace directory hashing
├── ignore.py # .gitignore matching shared by tools/security/sca
├── rules.py # project rules file discovery (AGENTS.md, ...)
├── codeindex.py # BM25 index + ranking behind the code_search tool
├── hunks.py # per-hunk diff split/reconstruct behind write_file/edit_file review
├── mcp_client.py # MCP (Model Context Protocol) stdio client
├── webfetch.py # fetch_url tool: SSRF-checked HTTP fetch + HTML->text
└── providers/
├── base.py # Backend interface (owns native msg format)
├── anthropic_backend.py # Messages API: streaming, thinking, caching
└── openai_backend.py # any /v1/chat/completions endpoint
The agent loop is provider-agnostic: one streaming call per round; when the
model returns tool calls, Tythan Code executes them locally (asking you first
for anything mutating), sends results back and repeats until the turn ends.
Refusals, pause_turn and token-limit stops are handled explicitly.
Two pieces of session-level bookkeeping wrap that loop:
- Compaction (
compaction.py+Agent.maybe_compact) splits the message history into "rounds" (a user turn plus everything the agent did in response), and — once the estimated context in use crosses ~80% of the model's context window minus the reserved output budget — asks the backend to summarize every round except the most recentcompact_keep_roundsinto one message. EachBackendimplementsrender_round(native messages → plain text) andcomplete_text(one-shot, tool-free completion) to make this provider-agnostic; if the summarization call itself fails, Tythan Code logs it once and keeps working with the full history rather than looping on a broken call. - Checkpoints (
checkpoints.py+Agent._checkpoint_before) record each touched file's pre-turn content the first timewrite_file/edit_filetouches it in a turn, and persist the whole turn as one checkpoint under~/.tythancode/checkpoints/<hash of the workspace path>/./undopops the most recent one and restores every file it touched. - Code index (
codeindex.py+Agent._get_code_index) is built lazily on the firstcode_searchcall and kept in memory for the rest of the session.Agentdrops the in-memory instance afterwrite_file,edit_fileorrun_command(any tool that could have changed files on disk), so the next search always reflects current content instead of silently going stale. Rebuilding is also backed by a per-workspace JSON cache under~/.tythancode/index/<hash of the workspace path>/index.jsonkeyed by each file's(mtime, size): a file that hasn't changed reuses its cached chunks instead of being re-read and re-tokenized. The cache format is versioned (codeindex.CACHE_VERSION) so a future change to chunking or tokenization invalidates old caches automatically, and any read/parse failure just falls back to a full rebuild rather than serving corrupt data.
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 tythan_code-1.0.0.tar.gz.
File metadata
- Download URL: tythan_code-1.0.0.tar.gz
- Upload date:
- Size: 89.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 |
0437ca6783029f29abf3ec516ec9027c4fce57d847d0191d672313d39c5b0719
|
|
| MD5 |
894f48f9903cb6061368a019a9208c2e
|
|
| BLAKE2b-256 |
21d3ccb6e9e26f4a7781ca5a252caae8a360a516cc96124243cb261bb57eb19a
|
Provenance
The following attestation bundles were made for tythan_code-1.0.0.tar.gz:
Publisher:
publish.yml on TythanAI/Tythan-Code
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tythan_code-1.0.0.tar.gz -
Subject digest:
0437ca6783029f29abf3ec516ec9027c4fce57d847d0191d672313d39c5b0719 - Sigstore transparency entry: 2084390745
- Sigstore integration time:
-
Permalink:
TythanAI/Tythan-Code@dd989bfde97f2a353acfa09461f5a44a5a8526d3 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/TythanAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@dd989bfde97f2a353acfa09461f5a44a5a8526d3 -
Trigger Event:
release
-
Statement type:
File details
Details for the file tythan_code-1.0.0-py3-none-any.whl.
File metadata
- Download URL: tythan_code-1.0.0-py3-none-any.whl
- Upload date:
- Size: 68.9 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 |
d21d4a1066c9357cb90301eb3db395d7665f24cba72b0478bfeff6e412660c3f
|
|
| MD5 |
5eb809826e31f0564525415b45f6b9de
|
|
| BLAKE2b-256 |
d65feff097ac3ccfdc2e727e78a98a62d190c36643400346917c023ad6cdaa96
|
Provenance
The following attestation bundles were made for tythan_code-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on TythanAI/Tythan-Code
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tythan_code-1.0.0-py3-none-any.whl -
Subject digest:
d21d4a1066c9357cb90301eb3db395d7665f24cba72b0478bfeff6e412660c3f - Sigstore transparency entry: 2084390749
- Sigstore integration time:
-
Permalink:
TythanAI/Tythan-Code@dd989bfde97f2a353acfa09461f5a44a5a8526d3 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/TythanAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@dd989bfde97f2a353acfa09461f5a44a5a8526d3 -
Trigger Event:
release
-
Statement type: