- Rust 99.6%
- Nix 0.3%
|
Some checks failed
CI / nix (push) Failing after 2s
Replay empty or stale legacy compactions as audited no-ops while rejecting new invalid compaction facts before append. Summarize the prior compacted projection plus the new tail so compaction requests stay within provider context windows. Record an empty summary as a provider failure instead of poisoning the journal. |
||
|---|---|---|
| .github/workflows | ||
| crates | ||
| docs | ||
| fuzz | ||
| tests/fixtures | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CODE_STYLE.md | ||
| DEVELOPMENT.md | ||
| flake.lock | ||
| flake.nix | ||
| justfile | ||
| LICENSE | ||
| README.md | ||
| rust-toolchain.toml | ||
| SECURITY.md | ||
Fite
A local-first coding agent whose conversations are signed, replayable event journals—not opaque application state.
Fite combines the Goose agent runtime with a Nostr-native persistence and transport layer. It provides a scrolling terminal interface, workspace tools, Agent Skills, OpenRouter/OpenAI/Ollama providers, MCP and ACP integration, and verified sharing and forking. The default experience is one command: Fite starts its embedded loopback daemon, creates a session, and opens the TUI.
Fite is alpha software. The event format and command-line interface may still change before 1.0. Use exports for important sessions and review tool approvals carefully.
What is novel about Fite?
Fite's distinctive idea is that an agent session is a verifiable protocol, not just a transcript stored by a UI.
Verifiable conversation state
Every durable session fact is signed by a session-scoped authority and linked to its predecessor. A deterministic fold reconstructs the conversation, provider lifecycle, tools, approvals, deliveries, and recovery state. SQLite indexes and TUI models are disposable projections; the signed event journal is the source of truth.
This makes history independently checkable, allows public sessions to be replayed without trusting Fite, and gives forks an exact parent event rather than a best-effort copy of rendered chat.
Side effects are part of the protocol
Provider requests, tool requests, approvals, starts, outcomes, cancellation,
and delivery attempts are durable facts. After a crash, Fite never blindly
repeats a provider or tool call merely because a final UI message is missing.
An interrupted non-idempotent tool becomes tool.outcome-unknown, forcing an
explicit recovery choice.
Forking does not replay the world
A fork copies only verified Goose conversation-effect batches into a fresh session with new reader and writer capabilities. It does not rerun models, tools, or external deliveries. Read-only bundles can be replayed and forked without granting authority to continue the original journal.
Privacy is fixed at session genesis
New sessions are public by default: their signed content is plaintext and can be replayed or forked by anyone holding the events. Private and shared sessions encrypt durable content to an independent session-reader key. Commands remain encrypted to the session authority in every mode. Visibility cannot silently change halfway through a conversation.
One event boundary for every interface
The TUI, CLI, ACP server, Buzz adapter, and sync path all use the same authenticated command/query boundary. No interface gets a privileged in-process agent handle or its own authoritative conversation model. The embedded relay binds only to loopback and requires NIP-42 authentication.
Quick start
Fite currently supports x86-64 and AArch64 Linux through Nix.
Run it directly from the Git repository:
nix run git+https://git.cashu.dev/thesimplekid/fite
Or build a checkout:
git clone https://git.cashu.dev/thesimplekid/fite
cd fite
nix build
./result/bin/fite
Bare fite starts a local daemon when needed, creates a public session, and
opens the scrolling terminal chat. Type a message and press Enter. Use /help
for session, provider, approval, cancellation, skill, and display commands;
use /quit to exit. You do not need to run fite-daemon separately for normal
interactive use.
The composer supports persistent prompt history, Tab completion for slash
commands and workspace paths, Ctrl-J for multiline prompts, and Ctrl-E or
/editor for $VISUAL/$EDITOR. /provider <PROFILE> selects an exact
configured provider. Assistant Markdown and diff-like output receive lightweight
terminal highlighting.
When a session is created, Fite discovers AGENTS.md files from the repository
root through the selected working directory. Their exact contents and digests
are captured in session genesis so replay uses the same instructions even if the
working tree later changes. /instructions lists the captured files and
/instructions full displays their content. Instruction snapshots follow the
session visibility policy, so they are plaintext in public sessions.
Without provider configuration, Fite uses a deterministic local fake so the complete session and tool flow can be tested without an account.
For scripts and CI, fite run owns the complete daemon/session lifecycle and
exits after one durable answer:
fite run "summarize this repository"
fite run --cwd ./project --provider openrouter --model MODEL_ID --format jsonl < prompt.txt
Each invocation creates a replayable session. --mode, --max-turns,
--reasoning, --visibility, and --prompt-file provide per-run overrides;
jsonl emits a session record followed by the completed answer as
newline-delimited JSON.
Sessions can carry signed titles without changing their stable UUIDs. Use
/rename TITLE, search with /sessions QUERY, and select an exact title or UUID
prefix with /session MATCH. The CLI equivalents are fite rename and
fite list --search. fite fork SESSION --head CANONICAL_HEAD (or /fork HEAD)
branches from an exact verified point in the conversation; omitting the head
forks the latest state.
Configure a model provider
fite models or /models lists the built-in fake and the default model for
each locally configured profile without contacting a remote catalog. Select a
model with /model MODEL, and set a provider-neutral signed reasoning level
with /reasoning off|low|medium|high|max (CLI: fite reasoning SESSION LEVEL).
The Goose provider layer maps that level to each supported model's request
format.
Every completed provider response retains its reported token and cost fields in
the canonical journal. /usage, fite usage SESSION, and fite status SESSION
show cumulative input/output/total tokens, cost, and the most recent prompt's
percentage of the resolved model context window.
To use the Codex models included with a ChatGPT subscription:
fite login codex
fite
You can instead run /login inside the TUI. Fite opens the ChatGPT browser
flow and listens on 127.0.0.1:1455 for the callback. If the browser cannot
reach that callback (for example, across SSH), copy its final redirect URL,
paste it into the Fite prompt, and press Enter. /logout or
fite logout codex removes the locally cached tokens. Login creates a local
codex profile using chatgpt_codex and makes it the default.
OpenRouter is the simplest way to use models from multiple vendors:
fite config set-profile router \
--provider openrouter \
--model <OPENROUTER_MODEL_SLUG> \
--credential
fite config set-default router
fite
API credentials are read from a secure prompt and written to the owner-only
local provider registry. ChatGPT access and refresh tokens use a separate
owner-only OAuth file and refresh automatically. No credential or token is ever
placed in a Nostr event. OpenAI API-key profiles use --provider openai; for
Ollama, use --provider ollama and omit --credential.
Provider profile selection and model name are canonical session configuration.
Endpoints and secrets remain local. Environment variables are available as
explicit CI/container overrides, not as the primary interactive configuration
path. Run fite config to see the redacted effective configuration.
Agent turns default to at most 1000 consecutive tool-calling iterations. The limit is canonical session configuration, so it follows exported, replayed, and forked conversations:
fite config set-session-max-turns <SESSION_UUID> 100
Inside the TUI, /max-turns shows the effective value and /max-turns 100
changes it. Before the hard ceiling, Fite detects repeated identical calls,
alternating call cycles, and consecutive tool failures. It gives the model one
explicit chance to change course, then requests a tool-free final answer if the
same loop continues. Reaching a guard produces a normal, replayable assistant
response rather than failing the turn.
Fite automatically compacts provider context at 80% of the model context window
or the configured message bound. /compact (or fite compact <SESSION_UUID>)
requests it explicitly. The model-generated summary and its verified source
head are journaled, while the complete conversation remains canonical and
visible for replay or forks.
Coding tools and approvals
The model receives structured file tools scoped to the directory where its session was created, plus shell tools that use that directory as their working directory:
fite_read_file,fite_list_files, andfite_search_textare bounded, read-only operations.fite_write_fileandfite_edit_filemake atomic changes after explicit approval.fite_apply_patchvalidates and applies all-or-rollback batches of file additions, exact edits, deletions, and moves with a combined diff preview.fite_shellruns Bash with the Fite process's environment and access, bounded output, and an approval gate.fite_shell_start,fite_shell_poll,fite_shell_input, andfite_shell_cancelmanage bounded background commands for builds, servers, and other long-running jobs.fite_skilldiscovers Agent Skills by metadata and loads bodies only on demand.fite_delegategives a self-contained task to a child coding agent and returns its final answer. Passingtasksinstead runs up to four independent child sessions concurrently and returns every signed child session ID.
When a provider requests multiple independent file reads, listings, or text searches in one response, Fite executes them concurrently. Request/start facts and terminal outcomes are still committed in provider order, keeping replay and projection hashes deterministic. Mutations, shell commands, approvals, and MCP calls remain serialized.
Fite records tool request, review, approval, start, and outcome facts in the session
journal. The TUI clearly separates assistant text, tool activity, compact tool
results, approval prompts, and final answers. Enter /approve, /approve turn,
or /deny after reviewing a pending mutation. While automatic review is running,
the status says reviewer checking approval; waiting for your approval means
the next decision is yours. Reviewer failures and timeouts are named when control
passes to you, and submitting /approve or /deny produces an immediate local
acknowledgement while the signed decision is recorded. Active status also shows
minute-bucket elapsed time and the latest context usage/window (for example,
ctx 24k/200k) as a Tau-style right prompt. The editable input always begins at
the same column, and the right prompt disappears rather than colliding with a long
or multiline draft. Assistant text streams through signed ephemeral frames while
the completed provider message remains the only durable response.
After upgrading Fite, restart both the daemon and terminal client from the same build. Runtime discovery rejects incompatible daemon/client generations before the client can misread newer canonical event types.
Each session has a signed chat, review, approve, or auto tool mode.
review is the default: confined reads and structured workspace edits run
directly, while shell, MCP, and delegation calls are reviewed or shown to the
operator. Fite deliberately does not create a process, filesystem, or network
sandbox. Shell commands inherit the Fite process's effective access; run Fite
inside a container or sandbox at the launcher/deployment layer when confinement
is required.
approve asks the operator before every side effect, chat exposes no tools,
and auto skips prompts. Use /mode, or configure the CLI explicitly:
fite config set-mode review
fite config set-reviewer openrouter --model MODEL_ID
fite config set-session-mode <SESSION_UUID> auto
fite config set-tool-permission fite_shell ask
The selected session mode is replayable Nostr state. Per-tool overrides and
the default for new sessions stay owner-local in permissions.json. Reviewer
credentials also remain owner-local. Every completed review is signed by a
separate reviewer Nostr identity and embedded as verifiable evidence in the
canonical approval history; the reviewer can recommend one exact call or
escalate, but it never receives session-authority keys.
Delegation is Nostr-native rather than an invisible in-process prompt. Each
child receives a distinct session authority and signed subagent relationship
to the exact parent head, an isolated conversation, the parent's provider/tool/
MCP selections, and the same working directory. Its complete journal can be
listed, inspected, replayed, shared, or forked like any other session. Nesting
is capped at four, and a daemon needs at least one spare active-session slot.
For analysis before implementation, /plan on switches the current session to
read-only plan mode. The model can inspect the workspace, maintain a structured
plan with signed plan.updated facts, and pause for a bounded multiple-choice
question. The TUI displays the choices and resumes after /answer TEXT; headless
operators can use fite tools <SESSION_UUID> followed by
fite answer <SESSION_UUID> <QUESTION_ID> <ANSWER>. /plan displays the latest
folded plan and /plan off returns the session to review mode.
Project skills live at .agents/skills/<name>/SKILL.md or
.agents.local/skills/<name>/SKILL.md. Use /skills and
/skill <name> [arguments] interactively. See Agent Skills
for discovery precedence, frontmatter, bounds, and durability behavior.
Sessions, sharing, and recovery
# Create explicitly; public is the default.
fite create --visibility public
fite create --visibility private
fite create --visibility shared
# Resume the latest session or a specific session.
fite tui
fite tui <SESSION_UUID>
# Verify and inspect signed history.
fite verify <SESSION_UUID>
fite inspect <SESSION_UUID>
# Share replay/fork access without write authority.
fite share <SESSION_UUID> conversation.fite-bundle.json
# Export continuation authority, restore, and fork.
fite export <SESSION_UUID> continuation.fite-bundle.json
fite import conversation.fite-bundle.json
fite fork <SESSION_UUID> --visibility private
Exports are password-encrypted and never include the installation owner key.
share omits session write authority. Import verifies signatures, sequence,
predecessor links, object completeness, and the projection hash before making a
session available. NIP-77 relay synchronization is opt-in and uses the same
verification rules.
Architecture
| Layer | Responsibility |
|---|---|
fite-protocol |
Versioned event schemas, limits, encryption envelopes, golden fixtures |
fite-core |
Deterministic fold, lifecycle invariants, recovery actions, repository traits |
fite-store |
NDK/SQLite adapter, pagination, snapshots, backup, verified NIP-77 sync |
fite-gdk |
Goose state-machine adapter and atomic conversation-effect batches |
fite-app |
Daemon composition, TUI/CLI, coding tools, skills, ACP, MCP, and Buzz |
The default data directory follows the Linux platform convention and contains:
events.sqlite authoritative signed Nostr event store
projections.sqlite disposable indexes and session heads
keys.json owner, agent, interface, reviewer, and session keys (mode 0600)
providers.json provider profiles and credentials (mode 0600)
permissions.json owner-local tool defaults and overrides (mode 0600)
mcp.json owner-local named MCP server profiles (mode 0600)
chatgpt-codex.json local ChatGPT OAuth tokens (mode 0600, when logged in)
prompt-history.json owner-only terminal prompt history
runtime.json loopback relay discovery; present only while a daemon runs
Canonical ordering is sequence plus previous, never relay arrival time or a
Nostr timestamp. Token deltas and progress frames are ephemeral. Snapshots and
projections are derived and can be rebuilt from verified canonical facts.
Interfaces
fiteis the default interactive entrypoint and also provides headless create, submit, inspect, verify, status, configuration, export/import, fork, and sync commands.fite-daemonruns the local relay and agent lifecycle as a persistent process for headless or multi-interface deployments.fite-acpexposes ACP v1 over stdio for compatible editors and clients.fite-buzzis an opt-in native Buzz adapter with fail-closed access gates and a signed durable reply outbox. See Buzz integration.
Configure any number of named stdio MCP extensions locally, then enable up to eight of them in a session's signed configuration:
fite mcp add filesystem npx -- -y @modelcontextprotocol/server-filesystem .
# Secret environment values are prompted securely and never enter shell history.
fite mcp add hosted tool-command --env API_TOKEN -- --stdio
fite mcp enable <SESSION_UUID> filesystem
fite mcp list
The command and arguments remain machine-local; only stable profile names enter
Nostr events. /mcp manages the selected session from the TUI. ACP clients may
also supply per-session MCP servers. The legacy FITE_MCP_COMMAND and
FITE_MCP_ARGS_JSON override remains for CI compatibility, and all
side-effecting extension calls still pass through Fite's permission policy.
Security model
- The default relay is IPv4 loopback-only and requires NIP-42.
- Session authorities limit a leaked writer key to one journal.
- Private/shared canonical content uses NIP-44; public content remains signed plaintext by design.
- Provider credentials, raw keys, MCP environments, and authorization headers must never enter canonical payloads or logs.
- Network synchronization and native Buzz access are disabled until explicitly configured.
- A data-directory lease prevents two daemons from advancing one installation.
Read SECURITY.md before exposing external relays or tools. Please report vulnerabilities privately rather than opening a public exploit report.
Development
nix develop path:.
just quick-check
Run just final-check before tagging a release or changing dependency pins. It
adds the full Crane/Nix build and check graph. The workspace pins Rust 1.96.1,
Nostr Dev Kit, Goose, and the ACP SDK for reproducible protocol behavior.
Contributor setup is in DEVELOPMENT.md. Delivered alpha capabilities are summarized in the implementation record.
License
Fite is available under the MIT License.