Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Harness Integration (Claude Code Hooks)

Yupana can plug into an agent harness so it responds to edits synchronously, the way a language server reacts to a keystroke. The agent's edit tool call is the change event; a harness hook feeds it to Yupana, and Yupana replies inline — no tool call for the agent to remember.

For Claude Code this uses hooks.

Post-edit advisory (available now)

yupana hook post-edit reads the PostToolUse payload on stdin and, when the edited file has symbols called from other files, returns a cross-file blast-radius advisory as injected context.

Wire it in .claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          { "type": "command", "command": "yupana hook post-edit" }
        ]
      }
    ]
  }
}

After the agent edits src/auth.rs, it sees something like:

Yupana (tree-sitter): your edit to src/auth.rs touches symbol(s) with callers
elsewhere — re-check these still compile.
  authenticate <- 3 caller(s)
  verify_token <- 1 caller(s)
Impacted files: src/api/login.rs, src/api/session.rs

The advisory is emitted only when there is cross-file impact, and the hook never fails the harness (no output = nothing to say).

With the quipu feature and the work-item scope rung at advise, the same hook also delivers the out-of-ground notice as additionalContext: the edit has landed, nothing is blocked, and the agent is told — before its next action — that it stepped outside its work item's ground, with what the graph knows about that path (who worked it before, and how that went). This channel exists because a pre-edit systemMessage reaches the operator's pane, not the model's context; see the policy guard contract.

Work-item briefing (available now, quipu feature)

yupana hook session-start (SessionStart) injects the graph's knowledge of the agent's tracked work item into its context at assignment time — before the first edit, not at the first denial: the item's ground (paths prior work touched, with symbols and caller locality), the central entities around it (quipu pagerank), semantically similar past items with their outcomes so successful work gets reused, related in-flight items, the governed rules in force, and the scope posture. Silent when no plate or no quipu seam.

Candidate work-item identities are fetched in deduplicated batches of at most 32 entities, preserving each item's label and outcome without a network request per candidate. A failed batch contributes no identities and does not trigger individual retries. Search, context ranking, and the policy projection keep their existing freshness behavior; this does not cache a brief across sessions.

What lands in context is the L0 briefing: the item, its ground paths and the scope posture, plus a census of every section held back — one line each, naming how many items it holds and the real quipu_ask / quipu_context / quipu_project call that expands it. The census is the whole difference between a briefing that is small and one that is incomplete: a short briefing with no counts is indistinguishable from a graph that knew nothing. Sections with zero items are omitted entirely rather than shown as empty headings.

Division of labor with Bobbin: Bobbin's own hooks (bobbin hook install — inject-context on UserPromptSubmit, session-context/prime-context on SessionStart) own semantic code context; this briefing owns the governance/work-item context. Wire both side by side — the briefing deliberately does not nest a bobbin call, so the same context is never injected twice.

{
  "env": { "SHANTY_ROOT": "/gt", "SHANTY_AGENT": "polecat-3" },
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          { "type": "command", "command": "yupana hook session-start", "timeout": 15 }
        ]
      }
    ]
  }
}

Pre-edit guard (available now)

yupana hook pre-edit (PreToolUse) checks an edit before it lands against the calling tenant's capability scope, and can deny it with a reason the model can act on. Blocking is opt-in and off by default.

{
  "env": { "BOBBIN_ROLE": "polecat-3" },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          { "type": "command", "command": "yupana hook pre-edit", "timeout": 5 }
        ]
      }
    ]
  }
}

With a scope configured for that tenant (see Configuration), an over-reaching edit comes back as:

yupana: editing `src/core.rs` reaches 4 symbols (ceiling 2) and 4 files
(ceiling 1) — beyond the blast radius allowed for tenant `polecat-demo`.
Split this into a narrower change that touches fewer callers, or ask for a
wider capability scope. (tree-sitter tier: the reach is an approximation.)

The guard always fails open: every error, timeout, and unparseable payload allows the edit, because a guard that fails closed would brick every agent the moment Yupana is unavailable. Read the full contract before wiring it into a fleet — particularly the rules that allow is silence and that Yupana never exits 2.

The action surface (pre-bash)

yupana hook pre-bash (PreToolUse on Bash) records each command's resolved (verb, target, class) for the enforcement trace, and is record-only by default: it prints nothing unless a deployment explicitly sets [yupana.policy] action_scope (off out of the box), at which point a declared scope's allow_targets / deny_targets can advise or refuse a command. Commands whose target is not unambiguous from syntax are abstentions, never violations. See the guard contract.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "yupana hook pre-bash", "timeout": 5 }
        ]
      }
    ]
  }
}

Performance note

By default the hooks build the call graph transiently on each invocation. With a running resident daemon and [yupana.serve] use_daemon = true, both hooks become thin clients of the resident graph — no per-invocation build, which is what meets the sub-100ms budget a synchronous guard needs. The daemon being down degrades differently per hook: the pre-edit guard fails open loudly, the post-edit advisory falls back silently (it is advice, not enforcement). See the specification §5.9 (FR-30/FR-31).