# Scribe Integration

> How to use Scribe MCP tools correctly — logging, docs, topology, bugs, file reading, search

- Skill: `cortalabs/scribe-integration-2` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cortalabs/scribe-integration-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cortalabs/scribe-integration-2/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: CortaLabs (https://skillmd.com/u/cortalabs)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/cortalabs/scribe-integration-2

---

<!-- COUNCIL:GENERATED:BEGIN -->
<!-- Auto-generated by `council update` (generated by council update).
     Surface: skill | Path: scribe-integration/SKILL.md
     Do not edit by hand; edit the source template and regenerate. -->
<!-- COUNCIL:GENERATED:END -->

# Scribe Integration Guide

Scribe is the persistent audit trail for all Council work. Every significant action must be logged. Unlogged work is invisible to the team and to future agents.

> **This skill is THE canonical, complete reference for the Scribe MCP tool surface and workflow.** It documents every registered Scribe tool (see the [Full Tool Reference](#full-tool-reference) appendix), the mandatory startup sequence, the logging cadence, the document lifecycle, and bug/security reporting. If you are an agent or host that needs to discover or correctly call Scribe tools, this is the one-stop reference — re-open it any time with `/scribe-integration`. For first-time **install and connection** (getting Scribe running and reachable), see the separate `/scribe-onboarding` skill; this guide assumes Scribe is already connected.

## Evidence Family Boundary

- `scribe-integration` is the protocol entrypoint for Scribe work (startup sequence, logging cadence, docs lifecycle, bug/security reporting).
- Retrieval evidence (semantic search, citations, corpus refresh) belongs to `scribe-rag-workflow`.
- Runtime/log evidence (daemon/web/process telemetry, incident traces, log-plane checks) belongs to `log-observability`.
- Browser runtime validation belongs to a dedicated browser-validation skill package; do not expand this skill into browser troubleshooting procedures.

## Mandatory Startup Sequence

Before ANY work — reading files, editing code, planning — execute these two calls:

```python
# 1. Activate project (sets context for all subsequent calls)
set_project(agent="<your-name>", name="<project_name>", root="<repo_root>")

# 2. Load recent context (understand what's happened before you)
read_recent(agent="<your-name>", limit=5)
```

**Why this matters:**
- `set_project` ensures your `append_entry` calls go to the right project log
- Without `set_project`, logs are orphaned in the default project
- `read_recent` prevents duplicating work already done
- The base Scribe project is only for ephemeral tactical work; once a named workstream exists, stay on it
- Orchestrators must propagate the same active project to every delegated agent instead of silently falling back to the base project

**Skip these two steps = your work gets rejected.**

### Project Binding Is Sticky

`set_project` is not a per-log call.

- Call `set_project` once during startup for the active project.
- Do not call `set_project` before every `append_entry`.
- Keep using `append_entry`, `manage_docs`, `read_recent`, and related Scribe calls on the active project context.
- Re-run `set_project` only when the operator/orchestrator changes the active project, or when an `append_entry`/Scribe response indicates sentinel/fallback/base-project mode, project mismatch, or orphaned logging.

---

## Logging with append_entry

Log every 2-3 significant actions. If it's not logged, it didn't happen.

### Single Entry

```python
append_entry(
    agent="forge",
    message="Fixed JWT validation — expiry now checked with 15min grace period",
    status="success",
    meta={
        "reasoning": {
            "why": "JWT tokens were accepted after expiry, allowing stale sessions",
            "what": "Added expiry check with configurable grace period to auth.py:142",
            "how": "Read auth.py scan_only, identified missing check, added with config fallback"
        },
        "file": "src/council_mcp/web/auth.py",
        "line": 142
    }
)
```

### Status Levels

| Status | Use For |
|--------|---------|
| `info` | Investigation steps, reading files, planning |
| `success` | Completed work, passing tests, fixes verified |
| `warn` | Unexpected findings, degraded paths, skipped steps |
| `error` | Failures, blocked work, tool errors |
| `bug` | Bug discoveries (triggers bug tracking) |
| `plan` | Work plans, task decomposition, approach decisions |

### Bulk Entries (Backfilling)

When you have multiple actions to log at once:

```python
append_entry(
    agent="forge",
    items=json.dumps([
        {"message": "Scanned auth.py — found JWT validation at line 142", "status": "info"},
        {"message": "Identified missing expiry check", "status": "bug",
         "meta": {"file": "auth.py:142"}},
        {"message": "Added expiry check with 15min grace period", "status": "success"}
    ])
)
```

### Global Log (Milestones)

For repo-wide milestones (phase completions, major decisions):

```python
append_entry(
    agent="atlas",
    message="Phase 1 complete — auth system refactor shipped, 44/44 tests pass",
    status="success",
    log_type="global",
    meta={"project": "council_unified_platform", "entry_type": "milestone"}
)
```

### Reasoning Traces (Required)

Every `append_entry` for significant work MUST include reasoning in `meta`:

```python
meta={
    "reasoning": {
        "why": "research goal or decision point that prompted this action",
        "what": "constraints, alternatives considered, scope of change",
        "how": "methodology, tools used, steps taken"
    }
}
```

---

## Document Management with manage_docs

### Frontmatter, Status Intent, Topology, and Scaffold Quality Gates

- Narrative-doc frontmatter changes must use `frontmatter_update` with `metadata.frontmatter`.
- `status_update` is checklist-only; using it on narrative docs must be treated as an intent error (`DOC_STATUS_INTENT_MISMATCH`).
- Checklist item `metadata.status` is item state only; it must not update managed-doc frontmatter lifecycle `status`.
- Managed-doc lifecycle status must use Scribe's canonical values: `scaffolded`, `in_progress`, `ready`, `complete`, `stale`, `superseded`, `blocked`, or `archived`.
- Managed-doc frontmatter should include stable `id`, `doc_type`, `doc_name`, `status`, `summary`, `owners`, `tags`, and typed topology when relevant.
- Human-facing attribution should use display names such as `Forge`, `Atlas`, `Witness`, `Crucible`, `Blueprint`, `Arbiter`, `Loom`, and `Quill`; preserve opaque runtime IDs only as secondary provenance when Scribe provides them.
- Scaffold residue means not done; completion/readiness can be blocked with `DOC_NOT_DONE_SCAFFOLD_QUALITY`.
- Run `quality_check` before handoff on managed docs, run `quality_handoff_check` before clean clock-out/handoff claims, and run `project_health` before closeout.
- Configured log surfaces, including custom `logs:` entries in `.scribe/config/scribe.yaml`, are not readiness-quality targets.

Quality warnings to treat as authoritative:
- `SCF_PLACEHOLDER_BRACKET`
- `SCF_TEMPLATE_PROSE`
- `SCF_FAILED_WRITE_RESIDUE`
- `SCF_EMPTY_FINDING`
- `SCF_UNFILLED_APPENDIX`
- `SCF_TODO_ONLY_SECTION`
- `SCF_LOG_TEMPLATE_ONLY`
- `SCF_FRONTMATTER_MISMATCH`
- `SCF_LIFECYCLE_STATUS_MISMATCH`
- `SCF_INDEX_STALE`
- `SCF_INDEX_MISSING`
- `SCF_DOC_UNINDEXED`
- `SCF_NONCANONICAL_LOCATION`
- `SCF_CHANGELOG_ENTRY_ID_MISSING`
- `SCF_CHANGELOG_ENTRY_ID_INVALID`
- `SCF_CHANGELOG_SUMMARY_MISSING`
- `SCF_CHANGELOG_EVIDENCE_MISSING`
- `SCF_CHANGELOG_DUPLICATE_SOURCE_KEY`
- `SCF_CHANGELOG_RAW_PROGRESS_DUMP`
- `SCF_CHANGELOG_AMBIGUOUS_BODY_STATUS`
- `SCF_CHANGELOG_ESCAPED_NEWLINES`
- `SCF_RESEARCH_CONTEXT_DRIFT`

Topology and lifecycle warnings to treat as authoritative when present:
- `TOPOLOGY_MISSING_ID`
- `TOPOLOGY_DUPLICATE_ID`
- `TOPOLOGY_DANGLING_EDGE`
- `TOPOLOGY_INVALID_EDGE_SHAPE`
- `TOPOLOGY_READY_DEPENDS_ON_DRAFT`
- `TOPOLOGY_DEPENDENCY_CYCLE`
- `DOC_MISSING_SUMMARY`
- `DOC_STATUS_INVALID`
- `DOC_STATUS_TRANSITION_BLOCKED`
- `DOC_AGENT_ID_LEAK`
- `DOC_REGISTRY_MISSING`

### Document Topology MCP Usage

Use topology actions to keep the managed corpus deterministic and downstream-safe. These actions belong in normal Scribe workflow; do not invent a second registry, validator, semantic linker, or retrieval pipeline inside Scribe.

```python
manage_docs(
    agent="witness",
    action="topology_scan",
    dry_run=True
)

manage_docs(
    agent="witness",
    action="metadata_scan",
    dry_run=True
)

manage_docs(
    agent="forge",
    action="metadata_repair",
    metadata={"mode": "repair_safe"},
    dry_run=False
)

manage_docs(
    agent="witness",
    action="ingestion_manifest_inspect",
    dry_run=True
)
```

Repair modes:
- `report_only`: produce findings and perform no writes.
- `repair_safe`: apply deterministic fixes only, such as generated IDs, canonical missing status, scalar-to-list normalization, and safe metadata shells.
- `repair_assisted`: produce an operator/agent review plan for ambiguous fixes.

Topology fields:
- `depends_on`
- `supports`
- `validates`
- `supersedes`
- `blocked_by`
- `touches`
- `related_docs`

Downstream export boundary:
- Scribe may generate sanitized local artifacts such as `doc_topology.json`, `work_topology.json`, and `downstream_ingestion_manifest.json` under `.scribe/indexes/`.
- These artifacts are derived outputs, not a second source of truth.
- Downstream consumers may build retrieval or graph systems from them; Scribe itself must stay deterministic and must not add embeddings, transformer classification, semantic guessing, or graph-RAG behavior.

Canonical research/index guidance:
- Keep research docs in flat `.scribe/docs/dev_plans/<project>/research/`.
- Maintain `research/INDEX.md` as the canonical index surface.
- Treat noncanonical, stale, orphaned, or unindexed research states as warnings that must be resolved before done-state claims.
- Research docs for a named workstream must be created in the active Scribe project. A research artifact written to the repo root, base project, wrong dev-plan folder, wrong filename prefix, or another Scribe project is not accepted evidence.
- If a research doc lands in the wrong location/project, BLOCK downstream routing and use Scribe `manage_docs(action="rehome_doc", metadata={"target_project": "<active_project>"})` or the dedicated Scribe rehome-doc tool if exposed. Do not move managed docs with shell `mv`, `cp`, ad hoc file writes, or git-only renames.
- If `manage_docs(create)` lands a research artifact in the wrong place, rehome it before writing substantive content. The clean sequence is create -> verify path/project -> rehome if needed -> write body -> quality_check -> index/readback.
- Scribe quality checks are necessary but not sufficient. Coordinator/Witness should also scan for scaffold residue, duplicate headings, stale body status, noncanonical paths, escaped-newline sludge, and index drift before accepting research.

Project-level artifact guidance:
- Research docs belong in `research/INDEX.md`.
- Synthesis, review, architecture, phase-plan, checklist, and changelog documents are project-level artifacts, not research docs.
- Do not force synthesis/review/project-level docs into `research/INDEX.md`; rely on project-level artifact health and quality surfaces.

### Frontmatter Update MCP Usage

Use this for narrative-doc metadata, not checklist progress:

```python
manage_docs(
    agent="blueprint",
    action="frontmatter_update",
    doc_name="ARCHITECTURE_GUIDE",
    metadata={
        "frontmatter": {
            "status": "ready",
            "owners": ["blueprint"],
            "summary": "Architecture plan ready for Witness review"
        }
    },
    dry_run=True
)
```

Re-run with `dry_run=False` only after the preview shows the intended frontmatter keys. `created_by` and `edit_trace` are reserved lifecycle fields; do not try to author them manually.

### Quality Check MCP Usage

Use this before handoff on managed docs:

```python
manage_docs(
    agent="witness",
    action="quality_check",
    doc_name="ARCHITECTURE_GUIDE",
    dry_run=True
)
```

Treat blocking warnings as unfinished work. Lifecycle/status mismatch and changelog escaped-newline warnings are blockers, not cosmetic notes.

### Quality Handoff MCP Usage

Use this before claiming clean handoff, completion, or clock-out for managed-doc work:

```python
manage_docs(
    agent="witness",
    action="quality_handoff_check",
    dry_run=True
)
```

If `handoff_allowed` is false, fix the listed managed docs before handing work back. Scaffold placeholders, failed-write residue, unresolved blockers, and serious topology warnings are not acceptable final-state paperwork.

### Planning Doc Ownership vs Checklist Proof

- The coordinator may create and update the managed pre-research `SPEC` doc with the operator.
- That `SPEC` is problem-definition only: problem, goals, non-goals, constraints, and research questions. It is not an architecture doc, phase plan, or task package.
- A usable `SPEC` is concrete enough that Lens can answer it; if the open questions are mushy or solution-biased, keep refining before research starts.
- Blueprint owns planning-content updates in `ARCHITECTURE_GUIDE`, `PHASE_PLAN`, and the planning structure of `CHECKLIST` for non-trivial named work.
- The active coordinator owns verification evidence plus `CHECKLIST` status/proof after task packages complete.
- `SPEC` is the only coordinator-owned planning artifact before Blueprint runs.
- Do not rewrite planning docs after every package-level correction. Update checklist status/proof for completed packages, and only route planning-doc rewrites when broader plan boundaries change.
- In named Scribe projects, no code may continue when direction/scope has deviated from the documented plan. Either correct execution back to plan immediately or update the plan first.
- If major reshaping or new phases are required mid-stream, open a new named Scribe project and run a fresh planning cycle instead of overwriting prior planning docs in place.

### Critical Rule: `create` is NOT enough

`manage_docs(action="create")` scaffolds an **empty** document template. You MUST follow it with `replace_section` calls to write actual content.

```python
# Step 1: Create the scaffold (empty doc)
manage_docs(
    agent="lens",
    action="create",
    doc_name="RESEARCH_AUTH_PATTERNS",
    metadata={
        "doc_type": "research",
        "research_goal": "Understand existing auth patterns before refactoring"
    }
)

# Step 2: ALWAYS follow with replace_section for each section
manage_docs(
    agent="lens",
    action="replace_section",
    doc_name="RESEARCH_AUTH_PATTERNS",
    section="findings",
    content="""## Auth Pattern Findings

JWT validation lives in `src/council_mcp/web/auth.py:142`.
Current flow: token decode → signature check → expiry NOT checked.
Grace period config key: `council.auth.token_grace_seconds` (missing from DEFAULT_CONFIG).
"""
)

manage_docs(
    agent="lens",
    action="replace_section",
    doc_name="RESEARCH_AUTH_PATTERNS",
    section="recommendations",
    content="Add expiry check with configurable grace period. Add key to DEFAULT_CONFIG."
)
```

### Built-In `create` Doc Types

| `doc_type` | Use For | Sections |
|------------|---------|---------|
| `research` | Lens investigation output | findings, recommendations, confidence |
| `bug` | Bug reports | symptoms, root_cause, fix, verification |
| `security` | Security reports | findings, severity, remediation |
| `review` | Review or audit reports | summary, findings, verdict |
| `agent_card` | Persona / agent documentation | role, capabilities, constraints |
| `custom` | Council-specific managed docs such as a pre-research `SPEC` | user-defined |

### Standard Scaffold Families

These are the common generated project-doc surfaces used by Scribe tooling:

| Scaffold | Use For |
|----------|---------|
| `architecture` | Design docs |
| `phase_plan` | Phase plans |
| `checklist` | Task tracking |
| `progress_log` | Workstream progress trail |
| `doc_log` | Documentation change trail |
| `security_log` | Security-specific tracking |
| `bug_log` | Bug-specific tracking |
| `changelog` | Curated project outcome history |

For generic test organization, naming, markers, and placement across codebases, use `/test-taxonomy`.

### Changelog and Version Context

Use changelogs for accepted outcomes, not raw progress-log dumps.

- Author curated entries in the project `CHANGELOG.md`.
- Treat `.scribe/docs/GLOBAL_CHANGELOG.md` as derived output only.
- Reconcile global entries only from project entries with `entry_status: accepted`.
- Run `quality_check` before reconciliation.
- Run `preview_reconciliation` before `apply_global_changelog`.
- Preview and quality actions diagnose; they do not perform hidden mutation.

Required accepted-entry fields:
- `entry_id`
- `entry_status`
- `summary`
- `evidence_refs`

Identity and dedupe:
- `entry_id` format: `<yyyymmdd>:<slug>`
- source key: `(project_slug, entry_id)`

Status boundary:
- `entry_status` is changelog-entry state only.
- Managed-doc frontmatter lifecycle `status` remains separate and must be repaired through `frontmatter_update`.
- Body prose such as `Status: accepted` inside changelog entries is ambiguous; prefer explicit `entry_status`.

Version/context behavior is advisory:
- Scribe observes context from manual metadata first, then `pyproject.toml`, then optional git fallback, then `unknown`.
- There is no SemVer enforcement, no auto-bump, and no hidden release management.
- Missing/unknown version context is allowed and non-blocking.
- Historical research context can warn as drifted without overriding active code as source of truth.

Escaped-newline rule:
- A project `CHANGELOG.md` must be real multiline markdown.
- Literal serialized `\n` sludge in changelog content is a blocking `SCF_CHANGELOG_ESCAPED_NEWLINES` quality failure.
- Fix it by rewriting the changelog with real newlines, not by suppressing the warning.

### Editing Documents: Prefer `apply_patch`

**`apply_patch` is the primary edit action.** It uses context matching (not bare line numbers) so it handles document drift gracefully. Always `dry_run=True` first.

#### Unified diff mode (recommended for most edits)

```python
# Apply a unified diff — context lines anchor the edit even if line numbers drifted
manage_docs(
    agent="forge",
    action="apply_patch",
    doc_name="architecture",
    patch="""--- before
+++ after
@@ -5,3 +5,4 @@
 ## Components

 Current auth uses basic JWT decode.
+Added expiry validation with 15s grace period.
""",
    dry_run=True  # ALWAYS dry_run first, then re-run with dry_run=False
)
```

#### Structured edit mode (for targeted line/section replacement)

```python
# Replace a specific section by anchor
manage_docs(
    agent="forge",
    action="apply_patch",
    doc_name="architecture",
    edit={"type": "replace_section", "section": "findings", "content": "Updated findings..."}
)

# Replace a block by anchor marker
manage_docs(
    agent="forge",
    action="apply_patch",
    edit={"type": "replace_block", "anchor": "<!-- ID: constraints -->", "content": "New constraints..."},
    doc_name="architecture"
)
```

**Why `apply_patch` over `replace_range`:**
- Context lines act as anchors even when line numbers shift
- Smart 3-tier matching: exact position, frontmatter offset, then full-document search
- Clear diagnostics when context doesn't match
- Handles multi-hunk patches atomically

### Other Edit Actions

#### `replace_range` (when you know exact line numbers)

**Line number coordinate system:** By default, `replace_range` called via the MCP tool uses **file-relative** line numbers (matching what `read_file` returns). This means you can use line numbers directly from `scan_only` or `line_range` output.

```python
# Line numbers from read_file work directly
manage_docs(
    agent="forge",
    action="replace_range",
    doc_name="phase_plan",
    start_line=45,   # file-relative (includes frontmatter in count)
    end_line=50,
    content="New content for these lines"
)

# For body-relative line numbers (legacy behavior, excludes frontmatter):
manage_docs(
    agent="forge",
    action="replace_range",
    doc_name="phase_plan",
    start_line=5,
    end_line=10,
    content="Body-relative replacement",
    metadata={"line_reference": "body"}
)
```

#### `replace_text` (find/replace with pattern matching)

```python
# Literal find/replace (default)
manage_docs(
    agent="forge",
    action="replace_text",
    doc_name="architecture",
    metadata={"find": "old_term", "replace": "new_term", "replace_all": True}
)

# Regex mode
manage_docs(
    agent="forge",
    action="replace_text",
    doc_name="architecture",
    metadata={"find": r"v\d+\.\d+", "replace": "v2.3", "match_mode": "regex"}
)

# Scoped to a section
manage_docs(
    agent="forge",
    action="replace_text",
    doc_name="architecture",
    metadata={"find": "TODO", "replace": "DONE", "scope": "section:findings"}
)
```

#### `append` (add content to end of doc or section)

```python
# Append to a section (inside = immediately after anchor)
manage_docs(
    agent="forge",
    action="append",
    doc_name="architecture",
    section="constraints",
    content="- New constraint added",
    metadata={"position": "inside"}  # "before" | "inside" | "after" (default)
)
```

### Checklist Updates

```python
# Mark a checklist item as done (with proof)
manage_docs(
    agent="forge",
    action="status_update",
    doc_name="checklist",
    section="task_auth_fix",
    metadata={"status": "done", "proof": "tests/test_auth.py::test_jwt_expiry PASSED"}
)
```

`section` may be a heading/section id or an inline item id such as `<!-- id: p4-task-3 -->`.
The helper should update exactly the targeted checklist item. If it appends a duplicate item, rewrites neighboring items, or cannot find an existing inline id, treat that as tool friction and fix/report it before final handoff.

---

## Bug Reporting

Every discovered bug MUST be logged immediately in the active Scribe trail; never hide, defer, or silently absorb discovery. This immediate-visibility rule applies to every agent; it does not transfer Mantis's diagnosis/repair authority to other roles.

Tiny in-contract defects remain attached to the active work item and current Scribe trail and are corrected through the active owner/validation loop. They do not automatically require `open_bug`, a standalone report, or a `link_fix` lifecycle.

Open a durable case immediately when severity, recurrence, cross-session coordination, security significance, knowledge value, operator direction, or Atlas routing warrants it. Preserve Mantis's diagnosis/repair authority for unknown, intermittent, flaky, runtime, startup, state-sensitive, or recurrence-prone failures; this policy changes case activation and ceremony only, not tool or runtime semantics.

After the durable-case threshold is met, preserve the complete evidence, report, and fix-link lifecycle:

```python
# Step 1: Open the durable case
open_bug(
    agent="forge",
    title="JWT tokens accepted after expiry",
    symptoms="Authenticated requests succeed with tokens expired >24h ago",
    category="logic"  # logic | runtime | config | data | integration | performance
)

# Step 2: Create the bug report doc scaffold
manage_docs(
    agent="forge",
    action="create",
    metadata={
        "doc_type": "bug",
        "category": "logic",
        "slug": "jwt-expiry-not-checked",
        "severity": "high",  # critical | high | medium | low
        "title": "JWT tokens accepted after expiry"
    }
)

# Step 3: Write each section
manage_docs(
    agent="forge",
    action="replace_section",
    doc_name="jwt-expiry-not-checked",
    section="symptoms",
    content="Authenticated requests succeed with JWT tokens expired >24 hours ago. No error returned."
)

manage_docs(
    agent="forge",
    action="replace_section",
    doc_name="jwt-expiry-not-checked",
    section="root_cause",
    content="auth.py:142 — `_validate_token()` checks signature but not `exp` claim. JWT decode uses `verify_exp=False`."
)

manage_docs(
    agent="forge",
    action="replace_section",
    doc_name="jwt-expiry-not-checked",
    section="fix",
    content="Set `verify_exp=True` in jwt.decode() call. Add 15s grace period via `council.auth.token_grace_seconds`."
)

# Step 4: Link the fix when resolved
link_fix(
    agent="forge",
    case_id="BUG-jwt-expiry-not-checked",
    artifact_ref="src/council_mcp/web/auth.py:142",
    landing_status="merged"
)
```

---

## File Reading with read_file

**RULE: ALWAYS scan before you read.** Never load entire large files.

### Step 1: Scan First

```python
# Get structure without loading content — cheap and fast
read_file(
    agent="forge",
    path="src/council_mcp/web/auth.py",
    mode="scan_only",
    include_dependencies=True  # shows imports and dependency graph
)
```

The scan returns class names, function names, and line numbers. Use these to target your reads.

### Step 2: Read Only What You Need

```python
# Read a specific range (from line numbers in the scan)
read_file(
    agent="forge",
    path="src/council_mcp/web/auth.py",
    mode="line_range",
    start_line=130,
    end_line=165
)
```

### Read Modes

| Mode | Use For | Cost |
|------|---------|------|
| `scan_only` | Structure overview, line numbers, imports | Cheapest |
| `line_range` | Specific function or class | Cheap |
| `chunk` | Sequential chunks (chunk_index=[0,1,2]) | Medium |
| `page` | Paginated reading (page_number, page_size) | Medium |
| `search` | Pattern search within file | Medium |
| `full_stream` | Entire file (only for small files) | Expensive |

### Cross-Repo Reading

```python
read_file(
    agent="forge",
    path="/home/user/projects/scribe_mcp/src/server.py",
    mode="scan_only",
    include_dependencies=True,
    allow_outside_repo=True  # REQUIRED for paths outside current repo
)
```

---

## Search Patterns

### Search Codebase (Regex)

```python
search(
    agent="forge",
    pattern="class.*Manager",      # Regex pattern
    glob="**/*.py"                  # File pattern filter
)
```

```python
search(
    agent="forge",
    pattern="_get_active_council_id",
    glob="src/**/*.py"
)
```

### Search Log History

```python
# Find recent entries about a topic
query_entries(
    agent="forge",
    message="JWT",                  # Search term
    message_mode="substring"        # Substring match
)
```

---

## Anti-Patterns

### Wrong — Creating a doc without writing content

```python
# WRONG: create alone produces an empty document
manage_docs(agent="forge", action="create", doc_name="RESEARCH_X", metadata={...})
# Nothing was written — doc is empty
```

### Right — Create then replace_section

```python
manage_docs(agent="forge", action="create", doc_name="RESEARCH_X", metadata={...})
manage_docs(agent="forge", action="replace_section",
            doc_name="RESEARCH_X", section="findings", content="Actual findings here...")
```

### Wrong — Using replace_range for multi-step document edits

```python
# WRONG: line numbers drift between calls, second edit hits wrong lines
manage_docs(action="replace_range", doc_name="arch", start_line=10, end_line=15, content="...")
manage_docs(action="replace_range", doc_name="arch", start_line=20, end_line=25, content="...")
```

### Right — Use apply_patch with context matching

```python
# RIGHT: context lines anchor each hunk independently
manage_docs(action="apply_patch", doc_name="arch", patch="..unified diff..", dry_run=True)
```

### Wrong — Skipping set_project

```python
# WRONG: logs go to wrong project or fail silently
append_entry(agent="forge", message="Did something important", status="success")
```

### Right — Always set_project first

```python
set_project(agent="forge", name="my_project", root="/path/to/repo")
append_entry(agent="forge", message="Did something important", status="success")
```

### Wrong — Reading entire large files

```python
# WRONG: loads 800 lines when you need 20
read_file(agent="forge", path="src/big_file.py", mode="full_stream")
```

### Right — Scan then target

```python
read_file(agent="forge", path="src/big_file.py", mode="scan_only")
# See line 142 has _validate_token()
read_file(agent="forge", path="src/big_file.py", mode="line_range", start_line=140, end_line=165)
```

### Wrong — Not calling read_recent before work

```python
# WRONG: starting blind, may duplicate work already done
set_project(agent="forge", name="my_project", root="/path/to/repo")
# Immediately starts coding without checking recent progress
```

### Right — Always check recent context

```python
set_project(agent="forge", name="my_project", root="/path/to/repo")
read_recent(agent="forge", limit=5)  # Load what's already been done
# NOW start working
```

---

## Full Tool Reference

This appendix enumerates **every** Scribe MCP tool the server registers, so an agent or host can discover the entire surface from this skill alone. The deep workflow sections above cover the core tools in detail; this table is the complete inventory. Tools are surfaced to hosts as `mcp__scribe__<name>` (the prefix depends on how the server is registered in your client).

**Trust tiers** come from each tool's contract wrapper and drive the MCP `annotations` a host sees:

| Tier | `annotations` | Meaning |
|------|---------------|---------|
| read-only | `readOnlyHint: true` | Reads/inspects only; never mutates state |
| additive (write) | `idempotentHint`/append semantics | Appends new records (logs, cases, events); does not rewrite existing state |
| stateful (write) | write, non-destructive | Mutates project/session/doc/reminder state in place |
| destructive (write) | `destructiveHint: true` | Removes or resets data; use deliberately |

> **Install/connection is NOT in this skill.** Getting Scribe installed and reachable (`pip install scribe-mcp`, the one-command local-Postgres wizard, env vars) lives in the separate `/scribe-onboarding` skill. Everything below assumes Scribe is already connected.

### Project & Context

| Tool | Tier | Purpose / When to use |
|------|------|------------------------|
| `set_project` | stateful | Bind the active project context for this session. **First call of every session.** Sticky — call once, not per log. |
| `get_project` | read-only | Return the active project selection (resolving defaults). Use to confirm what context you're bound to. |
| `list_projects` | read-only | List projects registered for the current repo (or all repos with `global_mode=True`). Use to find an existing workstream. |
| `delete_project` | destructive | Delete or archive a project and all associated data. Deliberate cleanup only. |
| `authorize_repo_root` | stateful | Issue a session-bound grant authorizing a bind to an external repository root. Needed before working outside the primary repo root. |

### Logging & Log Inspection

| Tool | Tier | Purpose / When to use |
|------|------|------------------------|
| `append_entry` | additive | Record an audit-trail log entry (single or bulk). **Log every 2-3 significant actions.** The primary "record what I did" tool. |
| `read_recent` | read-only | Load the most recent project log entries. **Second call of every session** (rehydrate before working). |
| `query_entries` | read-only | Search the project log history by message/term. Use to find prior work on a topic. |
| `progress_log_projection` | read-only | Public-safe readiness/render projection of the progress or doc-update log without mutating canonical logs. |
| `analyze_logs` | read-only | Log-intelligence analysis over a given log file path. Inspection only. |
| `rotate_log` | stateful | Rotate one or more project log files with integrity guarantees. Maintenance/admin. |

### Documents

| Tool | Tier | Purpose / When to use |
|------|------|------------------------|
| `manage_docs` | stateful | The document-governance router: create scaffolds, `replace_section`, `apply_patch`, `status_update`, `frontmatter_update`, `quality_check`, topology, changelog, and more. See the deep section above. |
| `generate_doc_templates` | additive | Render the standard project doc templates (architecture, phase plan, checklist, logs). Overwrites blocked unless `force=True`; progress logs always preserved. |

### Bugs, Security & Traceability

| Tool | Tier | Purpose / When to use |
|------|------|------------------------|
| `open_bug` | additive | Open a durable bug case (per-day stable ID) and scaffold its report doc after the durable-case threshold is met. Every discovery is still logged immediately in the active Scribe trail. |
| `open_security` | additive | Open a security case (per-day stable ID) and scaffold a detailed security report doc. |
| `list_open_cases` | read-only | List open bug/security cases from the shared case registry (filter by type/project/repo). |
| `link_fix` | additive | Link a fix artifact (`file.py:line`) to a case with a landing status (e.g. `merged`). |
| `append_event` | additive | Append a general sentinel event to `sentinel.jsonl` (append_entry-compatible args). Sentinel-mode logging. |

### File Reading & Search

| Tool | Tier | Purpose / When to use |
|------|------|------------------------|
| `read_file` | read-only | Structured code reading. **Always `scan_only` first**, then `line_range`/`chunk`/`page`/`search`/`full_stream`. See the deep section above. |
| `edit_file` | stateful | Safe exact-string file editing. Requires a prior `read_file` on the path this session; `dry_run=True` by default — set `False` to commit. |
| `search` | read-only | Regex search across the codebase with a `glob` filter. |

### Reminders

| Tool | Tier | Purpose / When to use |
|------|------|------------------------|
| `query_reminders` | read-only | Query reminder history and currently active reminders for a project. |
| `configure_reminders` | stateful | Configure reminder behavior (cadence/categories) for a project. |
| `reset_reminders` | destructive | Reset reminder cooldowns and/or reminder history for a project. |

### Diagnostics & Runtime (mostly internal)

| Tool | Tier | Purpose / When to use |
|------|------|------------------------|
| `scribe_doctor` | read-only | Runtime diagnostics for the current MCP server instance (config, roots, backend health). Run when Scribe behaves unexpectedly. |
| `read_write_barrier_state` | read-only | Public-safe Scribe write-barrier state for the active repo. |
| `scribe_owned_write_barrier_acquire_release_proof` | stateful | Acquire/release proof for the Scribe-owned write barrier. Internal coordination/proof tool. |
| `scribe_private_context_selector_readback` | read-only | Emit public-safe selector/readback labels without runtime or target contact. Internal proof tool. |
| `scribe_local_postgres_readiness_roundtrip_preflight` | read-only | Public-safe local-Postgres readiness roundtrip preflight. Internal readiness check. |

> `health_check` is also registered but is an internal liveness probe — hosts generally do not surface it for agent use.

### Quick usage for the useful-but-undocumented tools

The core workflow tools are covered in depth above. The snippets below cover the genuinely useful tools that the workflow sections don't already demonstrate.

```python
# Confirm / discover project context
get_project(agent="forge")                       # what am I bound to?
list_projects(agent="forge")                     # existing workstreams in this repo
list_projects(agent="forge", global_mode=True)   # across all repos

# Security case (parallel to open_bug)
open_security(
    agent="sentinel",
    title="Auth token logged in plaintext",
    symptoms="session_token appears in web_ui.log at INFO",
    severity="high",        # critical | high | medium | low
    category="data",
)
# then replace_section findings/severity/remediation, like a bug report

# See what cases are open
list_open_cases(agent="forge")                   # all open bug + security cases
list_open_cases(agent="forge", case_type="bug")  # filter by type

# Safe file edit (read_file first, dry_run preview, then commit)
read_file(agent="forge", path="src/auth.py", mode="line_range", start_line=140, end_line=160)
edit_file(agent="forge", path="src/auth.py",
          old_string="verify_exp=False", new_string="verify_exp=True",
          dry_run=True)   # preview; re-run with dry_run=False to commit

# Diagnose a misbehaving Scribe
scribe_doctor(agent="forge")                     # config, roots, backend health

# Reminders
query_reminders(agent="forge")                   # active reminders + history
configure_reminders(agent="forge", metadata={"stale_after_hours": 24})
```

**Tool count:** 30 registered tools (this appendix lists every one). The reference above is verified against the server's `@app.tool` registrations — if the surface changes, regenerate this skill from its `.j2` source rather than hand-editing the generated `.md`.
