organon
Structure-aware tools for AI agents. Tree-sitter code editing, web page navigation, search. No daemon, no JSON, just stdin.
- Stars
- 5
- Language
- Go
- Created
- Mar 18, 2026
- Updated
- Aug 29, 2026
Introduction
organon
Structure-aware tools for AI agents, plus small workflow CLIs used in the tta-lab workspace.
Organon provides commands that give logos agents structured perception of code, running inside a temenos sandbox.
$ src main.go --tree
├── [aE] func main() [L1-L15]
├── [bK] func handleRequest() [L17-L45]
└── [c3] type Config struct [L47-L55]
$ src main.go -s bK
func handleRequest(w http.ResponseWriter, r *http.Request) {
...
}
$ src replace main.go -s bK <<'EOF'
func handleRequest(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// new implementation
}
EOF
Commands
src — Source files
Read and edit code, config, and docs by symbol. Tree-sitter parses the file into an AST, assigns each symbol a 2-char ID, and you reference symbols by ID — no text matching, no multiline quoting problems.
src main.go --tree # symbol tree with IDs and line ranges
src main.go -s bK # read a symbol by ID
src replace main.go -s bK <<'EOF' # replace a symbol (stdin)
...
EOF
src insert main.go --after bK <<'EOF' # insert after a symbol (stdin)
...
EOF
src delete main.go -s c3 # delete a symbol
cat <<'EDIT' | src edit config.yaml # text replace (===BEFORE===/===AFTER===)
===BEFORE===
old text
===AFTER===
new text
EDIT
Supports symbol-aware extraction for Go, Rust, TypeScript, TSX, Python, C, C++, Java, Ruby, JavaScript, and many more via auto-inference. Language is detected from file extension. Markdown uses heading-based sections.
src edit is a text-based escape hatch for files where symbol editing is overkill (config files, unsupported languages, quick edits). It uses exact match with whitespace normalization fallbacks and works on any text file regardless of language support.
skill — Skill discovery
List, find, and read agent skills from project-local and global skill directories.
skill list
skill find "review and repair pull requests" --limit 3
skill get organon-src
nd-playlist — Navidrome playlists as code
Create, update, diff, and export Navidrome playlists through the Subsonic/OpenSubsonic API.
nd-playlist ping
nd-playlist search --json "小半 陈粒"
nd-playlist resolve playlists/navidrome/night.yaml
nd-playlist diff playlists/navidrome/night.yaml
nd-playlist apply --dry-run playlists/navidrome/night.yaml
nd-playlist apply --yes playlists/navidrome/night.yaml
nd-playlist export "Mandopop: Soft Night" > playlists/navidrome/mandopop-soft-night.yaml
nd-playlist export-all --output playlists/navidrome
nd-playlist radio diff playlists/navidrome/radios/cliamp.yaml
nd-playlist radio apply --yes playlists/navidrome/radios/cliamp.yaml
nd-playlist radio export > playlists/navidrome/radios/stations.yaml
Default config lives at ~/.config/nd-playlist/config.toml:
server = "https://music.example"
username = "ooneil"
password = "..."
--server, --username, --password, NAVIDROME_URL, NAVIDROME_USER, and
NAVIDROME_PASS override local config. If no password source is configured and
stdin is a terminal, nd-playlist prompts for the password. Playlist YAML
exports include song IDs but never include secrets.
Radio YAML uses name, stream_url, and optional homepage_url. radio diff
matches stations by stream URL and radio apply --yes creates only missing
stations. Keep machine-owned station files under playlists/navidrome/, which
is ignored by Git. Navidrome requires an admin account for this global change.
og — guarded forge operations
og runs GitHub PR and Git network operations directly inside the calling CLI or MCP
process. GitHub authentication uses repository-scoped installation tokens minted by a GitHub
App; GITHUB_TOKEN, GH_TOKEN, and github_token_env are not used. Forgejo
continues to use its existing token environment variables.
Create the real App only after both implementation PRs are merged, green, and the merged binary is ready to install. Register one App under a stable GitHub account and allow it to be installed by the other managed accounts. It needs no Marketplace listing, OAuth flow, callback, webhook, or organization permission. Grant only these repository permissions:
- Contents: read and write
- Pull requests: read and write
- Checks: read-only
- Actions: read-only
- Workflows: read and write
Install it on selected repositories only in tta-lab, GuionAI, and
LamplitIsles. Each installation owner must approve the permissions. Do not
grant Administration, Members, Secrets, Deployments, or other organization
access.
Before testing writes, configure every managed default-branch ruleset to require
a PR and required checks, restrict updates, and disallow force pushes and
deletion. Keep the App out of every bypass list. og can reach main and its
App token has Contents write permission, so GitHub rulesets are the hard merge
and default-branch boundary.
After downloading a private key, keep it outside the repository and configure OG:
install -d -m 700 ~/.config/ttal/og
install -m 600 ~/Downloads/your-app.private-key.pem \
~/.config/ttal/og/github-app.pem
cat <<'EOF' > ~/.config/ttal/og.toml
[github_app]
app_id = 123456
key_source = "file"
key_ref = "og/github-app.pem"
allowed_owners = ["tta-lab", "GuionAI", "LamplitIsles"]
[forgejo]
allowed_base_urls = ["http://forgejo.localhost:17480"]
EOF
chmod 600 ~/.config/ttal/og.toml
Before replacing a pre-direct-execution installation, stop and remove its user service with the old installed binary. On macOS:
OLD_OG="$HOME/.local/bin/og"
SERVICE="gui/$(id -u)/io.guion.og.daemon"
"$OLD_OG" daemon stop || true
"$OLD_OG" daemon uninstall || true
launchctl bootout "$SERVICE" 2>/dev/null || true
if launchctl print "$SERVICE" >/dev/null 2>&1; then
echo "old og service is still running; stop it before upgrading" >&2
exit 1
fi
rm -f "$HOME/Library/LaunchAgents/io.guion.og.daemon.plist"
On Linux:
OLD_OG="$HOME/.local/bin/og"
"$OLD_OG" daemon stop || true
"$OLD_OG" daemon uninstall || true
systemctl --user stop og.service 2>/dev/null || true
if systemctl --user is-active --quiet og.service; then
echo "old og service is still running; stop it before upgrading" >&2
exit 1
fi
rm -f "$HOME/.config/systemd/user/og.service"
systemctl --user daemon-reload
The direct-execution release has no daemon lifecycle commands; run this cleanup before replacing the old binary.
make install
og auth status --project organon
Clone URLs through OG so destination, authentication, and registration stay on one boundary:
og clone organon
og clone https://github.com/tta-lab/organon.git
og clone --alias forgejo https://codeberg.org/forgejo/forgejo.git
og clone --reference https://github.com/modelcontextprotocol/go-sdk.git
Alias clones use the registered path and canonical remote. URL project clones
derive ~/code/projects/<owner>/<repo> and register an alias plus remote.
Reference clones derive ~/code/references/<host>/<owner>/<repo> and remain
unregistered. Only GitHub, configured Forgejo roots, and anonymous generic
HTTPS are supported; callers cannot provide a destination or credentials.
For registered operations, projects.toml is the repository identity SSOT.
Immediately before a Git network operation, og checks the effective fetch URL
and, for writes, every push URL against that remote before resolving a token.
Normal repository hooks such as Lefthook run without bypasses.
Archived project entries remain useful context. They may read PR/CI state and
fast-forward the known default branch with og pull, but cannot push, tag,
create/modify/comment on PRs, or run pull's branch-cleanup path.
Keep the migration PAT active during rollout. In one selected repository from
each owner, run og auth status and require every permission to report ready.
Then use a disposable feature branch to verify og push, og pr create,
og pr view, og pr checks, and og pr comment. Confirm GitHub attributes the
push and PR activity to the App bot. Also verify that an SSH-configured origin
is unchanged on disk, an uninstalled managed write fails without fallback, and
a third-party public repository can pull anonymously but cannot write. Inspect
command errors and local Git configuration for credential material without
printing any secret values. Remove the downloaded key copy after this passes;
GitHub can issue a replacement, so no private-key backup is required.
Only after all three owners pass, remove local github_token_env keys and
GitHub PAT variables from ~/.config/ttal/.env and shell startup files. Run
the command again, repeat a representative App-only push and PR check, and then
revoke the migration PAT.
Installation tokens are automatic, memory-only, repository-scoped, and expire
after about one hour. The App private key is long-lived: it must never enter an
agent environment or Git child process. Direct git, gh, and arbitrary API
calls are outside OG's credential boundary and may still use personal
credentials; mandatory GitHub rulesets protect the default branch in those
paths.
For key rotation, create a replacement App key, install it with mode 0600,
run og auth status again, verify all owners, and then revoke and
remove the old key. Before PAT revocation, rollback means reinstalling the
previous og binary and stopping and uninstalling the old service with the existing
migration PAT.
After revocation, emergency rollback requires a new narrow temporary PAT; never
reactivate or reuse the exposed migration PAT.
MCP servers
project, og, and skill each provide a typed stdio MCP server. Configure
them as separate processes so clients can grant only the tools a session needs:
{
"mcpServers": {
"organon-project": { "command": "project", "args": ["mcp"] },
"organon-og": { "command": "og", "args": ["mcp"] },
"organon-skill": { "command": "skill", "args": ["mcp"] }
}
}
Use project_get or project_list to discover the exact five-field project
record: alias, name, path, canonical remote, and archive state. Active aliases
are single-layer names and cannot contain dots. Project registry updates are
visible on the next MCP call. The
repository-oriented og tools accept only that alias; they do not accept a
filesystem path, working directory, MCP root, file URI, or credential. clone
accepts a URL instead. The og MCP process loads configuration once and owns Git,
registration, policy, and forge credentials for its lifetime.
skill mcp exposes skill_list, skill_find, and skill_get. With no project
argument it searches only global skill directories. With an exact registered
alias, project-local skills take priority over global skills. Results use stable
source labels such as project:.agents instead of discovery-root paths.
skill_find accepts one natural-language query and an optional limit, then
ranks token matches across skill names, descriptions, and categories.
The CLI skill find command uses the same query validation, defaults, limits,
and ranking behavior.
Individual SKILL.md files larger than 1 MiB are rejected before parsing.
og mcp exposes twelve tools: auth status, clone, push, pull, PR create/find,
and PR get/modify/comment/checks/log/failures. It mirrors CLI current-branch
workflows against the registered checkout's current branch. Force push uses
force-with-lease and is rejected on the default branch. Pull retains the CLI's
guarded closed-PR branch cleanup. A positive PR ID selects a branch-free remote
operation; pr_get, modify, comment, checks, log, and failures use the current
branch when the ID is omitted. Tag remains CLI-only. Start a new og process after
changing og.toml. Run
<tool> mcp --help for each server's tool list and configuration details.
Pi extensions
Pi reaches Organon through three independently installable extension packages
(@tta-lab/pi-src, @tta-lab/pi-project, @tta-lab/pi-og)
instead of MCP configuration. Each carries a platform-matched native binary
and its own npm release. pi-src replaces Pi's built-in read and edit with
symbol-aware operations and exact multi-edit batches; pi-project registers
the project tools, while pi-og registers
og_auth_status, og_clone, og_pull, og_push, og_pr, and og_checks.
All six OG tools preserve the MCP domain behavior over a local subprocess. See
pi/README.md for installation, supported platforms, the read
and edit override behavior, and the opaque symbol-ID rules. The project, og,
and skill MCP servers remain for non-Pi clients; the project-scoped src MCP
server is removed.
Why
AI agents that work via shell commands (like logos) can't do multiline file edits. Every existing edit tool uses structured JSON parameters — {"path":"file","edits":[{"oldText":"...","newText":"..."}]} — which requires a tool-calling protocol, not shell.
Organon solves this by replacing text matching with symbol targeting. The LLM doesn't need to reproduce the old code — it asks for the symbol tree, picks an ID, and pipes the new code via a single heredoc. One stdin arg instead of two JSON fields.
Install
Homebrew
brew install tta-lab/ttal/organon
From source
CGO_ENABLED=0 go install github.com/tta-lab/organon/cmd/src@latest
CGO_ENABLED=0 go install github.com/tta-lab/organon/cmd/skill@latest
CGO_ENABLED=0 go install github.com/tta-lab/organon/cmd/project@latest
CGO_ENABLED=0 go install github.com/tta-lab/organon/cmd/og@latest
CGO_ENABLED=0 go install github.com/tta-lab/organon/cmd/nd-playlist@latest
From release
Download binaries from GitHub Releases.
How it fits
temenos (sandbox)
├── organon tools (pre-installed)
│ ├── src ← structure-aware file read/edit
│ ├── skill ← skill discovery
│ ├── project ← registered project discovery
│ └── og ← guarded Git and forge operations
├── standard tools (cat, ls, grep)
└── user code
logos (agent loop)
├── LLM writes: $ src main.go --tree
├── temenos executes in sandbox
├── output fed back to LLM
└── LLM writes: $ src replace main.go -s bK <<'EOF' ... EOF
Design
- Small cores, thin adapters — CLI and MCP commands share typed internal
services instead of duplicating business rules. Most commands parse, act,
and exit;
ogcomposes its credentials and policy in the calling process. - Stdin for content — new code goes through heredoc. One multiline arg, not two.
- 2-char IDs — base62 identifiers for symbols/sections, same system as flicknote.
- Tree-sitter — syntax-level AST parsing. No LSP server needed.
- Language detection — from file extension. No
--languageflag.
The name
Aristotle's Organon (ὄργανον, "instrument") was his collected works on logic — the toolkit that made reasoning possible. These tools are the instruments through which logos reasons about code.
| Project | Role |
|---|---|
| temenos | The boundary — sandbox isolation |
| logos | The reason — agent loop |
| organon | The instruments — perception and action |
License
Apache-2.0