ikigai-dev-server 0.2.0

A standalone, linkage-gated ikigai server for development tooling: git/gh/cargo + graphs + the browse family (persistent explanations/annotations), exec and llm rate-limited, over IPC.
ikigai-dev-server-0.2.0 is not a library.

ikigai-dev-server

A standalone, linkage-gated ikigai server for development tooling. Its Cargo.toml is the module manifest: the binary composes a curated space and links only what it serves.

ikigai-dev [socket] [flags]      # default: ~/.ikigai/dev.sock
ikigai --connect <socket>        # drive it from the REPL
ikigai-dev --help                # flags + the config-file grammar

What it serves

resource from
urn:system:exec, urn:repo:* ikigai-repo — git/gh/cargo as capability-gated resources
urn:rdf:* ikigai-rdf — graph union/diff/transrept
urn:sparql:* ikigai-sparql — query
urn:repo:{repo}:tree/file/state/hash/explain/…, urn:annotation:* ikigai-browse — the browse family, when configured (see below)
urn:llm:* ikigai-llm — the explain seam's derivation engine, mounted only alongside browse

Run it in a project directory and it serves that project's git state (source urn:repo:status, :log, :branch), or pass dir= for another repo.

The browse family (opt-in)

This server owns the browse store on a machine (decision of record): the persistent explanation/annotation archive is RocksDB under an exclusive lock, so ONE process holds it and everyone else prefer-mounts this server's socket — which is why the default socket is the stable ~/.ikigai/dev.sock rather than something under $TMPDIR that churns across reboots.

Configure it in ~/.config/ikigai/dev.toml (flags override the file; there is deliberately no environment-variable channel):

socket = "~/.ikigai/dev.sock"                # this IS the default

# One line per root; the URN repo name is the directory's basename.
browse.root = "~/git-personal/ikigai-core"
browse.root = "~/git-personal/ikigai-cli"

# Optional once a root exists:
browse.store = "~/.ikigai/browse-store"      # this IS the default
browse.file_model = "coder"                  # urn:llm:coder:ask
browse.dir_model = "ask"                     # urn:llm:ask
browse.file_max_tokens = 400
browse.dir_max_tokens = 600

No browse.root ⇒ no browse family at all (and no urn:llm:*) — the original curated surface, unchanged. A browse.* tuning without a root fails loud at startup: half-configured must never come up looking healthy. With roots, the store opens (or fails loud — never a silent in-memory archive), the bundled vocabulary loads, and urn:sparql:* binds over the same store, so one query joins ik:Explanation and oa:Annotation rows live.

Every other process on the machine reaches the family through this socket (in the main host's ~/.config/ikigai/config.toml):

mount = "prefer urn:repo:=~/.ikigai/dev.sock"
mount = "prefer urn:annotation:=~/.ikigai/dev.sock"

The LLM provider registry is the shared ~/.config/ikigai/llm.json (absent ⇒ a local Ollama default; present-but-unparseable ⇒ loud).

Why linkage-gating

ikigai mcp --grant dev on the omnibus binary config-gates — it hides the calendar tools, but their code is still linked and reachable in-process. This binary doesn't compile them in at all: EventKit and the calendar are not present, so a flaw in either cannot be reached. The security bound is the dependency list, not a runtime check.

ikigai-llm is linked — deliberately, and only mounted when browse is configured. The explain seam derives through urn:llm:*, and ikigai-llm is an outbound HTTP client to local inference servers — not the EventKit/TCC class of platform authority the gating posture exists to exclude. The rejected alternative (mounting urn:llm: from the main host) would couple every fresh explanation to the main host's uptime — the dev seam would degrade with the very process it exists to stand apart from.

On top of that, the expensive seams are wrapped in a RateLimit: 30 subprocess spawns/min on exec, 120 reads/min on urn:repo:, and 30 asks/min on urn:llm: (derivations are expensive; the limit governs explain's internal asks too, since subrequests resolve back through the overlay). Pure local graph ops pass unlimited.

Security posture (honest)

Three real bounds today — linkage (only these modules exist), rate-limiting (exec and llm are capped), and the transport's peercred check (owner-only socket). A per-scope capability ceiling enforced server-side is the "capability-on-the-wire" work; until then the local owner is trusted and the reachable surface is bounded by what is linked and limited. Browse's own capability story (urn:cap:browse:read:*, urn:cap:annotate) comes with the crate. An MCP face (so an agent connects under a grant) is a fast-follow.

License

MIT OR Apache-2.0.