Skip to content

Agent Protocol

Nib delegates all AI operations to external agent backends — standalone executables that communicate with nib via JSON over stdin/stdout. This page specifies the protocol so you can implement a backend for any AI provider.

Discovery

Nib finds the active backend by name:

  1. NIB_AGENT environment variable (highest priority)
  2. git config --get nib.agent (per-project)
  3. Default: claude

The name maps to an executable: nib-agent-<name>. For example, agent name ollama maps to nib-agent-ollama on PATH.

Invocation

Nib runs the agent binary as a subprocess:

  • Working directory is set to the project root.
  • stdin receives a JSON request object (pipe mode) or is passed through to the terminal (interactive mode).
  • stdout receives the JSON response (pipe mode) or is passed through to the terminal (interactive mode).
  • stderr is always passed through to the terminal. Use it for diagnostic messages.
  • Exit code 0 means success. Non-zero means failure.

Pipe vs interactive mode

Pipe operations (scene-proof, chapter-proof, voice-check, continuity-check, continuity-ask, continuity-index, project-scaffold) send the request as JSON on stdin and expect a JSON response on stdout.

Interactive operations (scene-critique, chapter-critique, character-talk) need the terminal for user interaction. The request is written to a temporary file and its path is passed via the NIB_AGENT_REQUEST_FILE environment variable. The backend reads the request from this file (and deletes it), then uses stdin/stdout/stderr for the interactive session. No JSON response is expected.

Request format

Every operation sends a single JSON object:

{
  "operation": "scene-proof",
  "dir": "/absolute/path/to/project",
  "paths": ["scenes/foo.md", "scenes/bar.md"],
  "character_slug": "lance-thurgood",
  "question": "Who drives Bo to Elko?",
  "range": "1-5",
  "context": "...",
  "schema": { },
  "session": { "id": "...", "resume": false, "new": false },
  "project_name": "my-novel"
}

All fields except operation are optional. Which fields are present depends on the operation.

Field reference

FieldTypeDescription
operationstringRequired. The operation to perform.
dirstringAbsolute path to the project root.
pathsstring[]Scene/chapter file paths (relative to project root).
character_slugstringCharacter identifier (e.g. lance-thurgood).
questionstringPlain-English question about the manuscript.
rangestringChapter/scene range to scope a query (e.g. 1-5).
contextstringPre-assembled prompt content.
schemaobjectJSON Schema for structured output (continuity-index only).
sessionobjectSession management options for interactive operations.
project_namestringProject name for template substitution (project-scaffold only).

Response format

All pipe operations return a JSON object on stdout with a type field that is either "success" or "error".

Success

{
  "type": "success",
  "operation": "scene-proof",
  "text": "3 comma fixes, 1 apostrophe."
}

Nib validates that type is "success" and operation matches the requested operation.

Error

{
  "type": "error",
  "error": "model not available"
}

Backends should prefer structured errors over stderr when possible. Nib surfaces the error field directly to the user.

Operations

scene-proof

Mechanical proofreading of scene files. Fix grammar, punctuation, spelling, typos, and formatting. Do not make taste decisions or tighten prose. Edit files directly as a side effect.

Request fieldspaths, dir
Responsetext (summary of fixes)
Used bynib ma proof (with dotted scene refs)

chapter-proof

Same as scene-proof but at chapter scope. The paths field contains all scenes in the chapter.

Request fieldspaths, dir
Responsetext (summary of fixes)
Used bynib ma proof (with whole-chapter refs)

scene-critique

Interactive editorial review of a scene. The backend takes over the terminal for a conversation about prose quality, pacing, voice, and purpose.

Request fieldspaths, dir
Responseinteractive (no JSON response)
Used bynib ma critique (with dotted scene refs)

chapter-critique

Interactive editorial review of a chapter. The paths field contains all scenes in the chapter in narrative order.

Request fieldspaths, dir
Responseinteractive (no JSON response)
Used bynib ma critique (with whole-chapter refs)

voice-check

Analyze character voice consistency across sampled scenes. Read the character’s profile and check that their dialogue and POV narration match their established voice.

Request fieldscharacter_slug, paths, dir
Responsetext (analysis)
Used bynib ma voice

continuity-check

Detect continuity errors in the specified scenes. Check for contradictions in facts, timelines, character knowledge, and physical details.

Request fieldspaths, dir
Responsetext (findings)
Used bynib ct check

continuity-ask

Answer a research question about the manuscript. The backend should use available tools to find evidence before answering.

Request fieldsquestion, range (optional), dir
Responsetext (answer)
Used bynib ct ask

continuity-index

Extract structured continuity data from a scene. The context field contains the assembled prompt and the schema field contains the JSON Schema the response must conform to.

Request fieldscontext, schema, dir
Responsedata object conforming to provided schema
Used bynib ct index
{
  "type": "success",
  "operation": "continuity-index",
  "data": { }
}

The backend is responsible for enforcing schema compliance — how it does so is implementation-specific (JSON mode, guided generation, post-validation, etc.).


character-talk

Interactive in-character interview. The context field contains a pre-assembled prompt with the character’s profile and story recap through a specific scene.

Request fieldscontext, session, dir
Responseinteractive (no JSON response)
Used bynib pr talk

Session options:

FieldTypeMeaning
idstringSession identifier. Use for persistence/resumption.
resumeboolResume an existing session instead of starting new. When true, context is empty.
newboolDelete any existing session with this ID and start fresh.

Session persistence is backend-specific.


project-scaffold

Write agent-specific project files during nib init. Non-interactive.

Request fieldsdir, project_name
Responsefiles array of relative paths created
Used bynib init
{
  "type": "success",
  "operation": "project-scaffold",
  "files": [
    "CLAUDE.md",
    ".claude/skills/copy-edit/SKILL.md"
  ]
}

Error handling

Backends have two ways to report errors:

  1. Structured (preferred): Return {"type": "error", "error": "message"} on stdout with exit code 0. Nib surfaces the message directly.
  2. Process-level: Write to stderr and exit non-zero. Nib captures stderr and includes it in the error message.

For interactive operations, only process-level errors apply since the backend owns stdout.

Design principles

The protocol defines what to do, not how. Each operation is a domain concept (proof, critique, voice-check) rather than a generic AI primitive (complete, extract). This means:

  • Backends own prompt construction. Nib sends structured data (file paths, character slugs, questions). The backend decides how to prompt its model.
  • Backends own execution strategy. Whether to use tools, streaming, multiple passes, or guided generation is the backend’s decision.
  • Backends own configuration. Effort levels, temperature, model selection, and tool permissions are internal to the backend.
  • Swapping backends changes implementation, not behavior. Every backend implements the same operations with the same semantic contract.

Minimal example

A backend that handles proof operations (useful for testing):

#!/usr/bin/env bash
# nib-agent-echo

request=$(cat)
operation=$(echo "$request" | jq -r .operation)

case "$operation" in
  scene-proof|chapter-proof)
    printf '{"type":"success","operation":"%s","text":"No issues found."}\n' "$operation"
    ;;
  project-scaffold)
    echo '{"type":"success","operation":"project-scaffold","files":[]}'
    ;;
  scene-critique|chapter-critique|character-talk)
    echo "Interactive operations not supported" >&2
    exit 1
    ;;
  *)
    printf '{"type":"error","error":"unknown operation: %s"}\n' "$operation"
    ;;
esac

Make it executable, put it on PATH as nib-agent-echo, and test with NIB_AGENT=echo nib ma proof 1.1.

Reference implementations

  • cmd/nib-agent-claude/ — Claude Code CLI backend (skills, session management)
  • cmd/nib-agent-local/ — Local model backend (OpenAI-compatible API, tool loop)