# https://github.com/BrettNye/stoa 项目说明书

生成时间：2026-05-16 00:38:52 UTC

## 目录

- [Introduction to Stoa](#introduction)
- [Core Concepts and Vocabulary](#concepts-vocabulary)
- [Architecture and Design](#architecture-design)
- [Event Bus System](#event-bus-system)
- [Agent Profiles and Evolution](#profiles-evolution)
- [Task Workflow System](#task-workflow)
- [Channels and Claims](#channels-claims)
- [Runtime Adapters](#runtime-adapters)
- [Sync Agents and Skills](#sync-agents-skills)
- [Tool Categories Reference](#tool-categories)

<a id='introduction'></a>

## Introduction to Stoa

### 相关页面

相关主题：[Core Concepts and Vocabulary](#concepts-vocabulary), [Architecture and Design](#architecture-design)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/BrettNye/stoa/blob/main/README.md)
- [src/core/profiles.ts](https://github.com/BrettNye/stoa/blob/main/src/core/profiles.ts)
- [src/core/pokemon.ts](https://github.com/BrettNye/stoa/blob/main/src/core/pokemon.ts)
- [src/core/synthesize.ts](https://github.com/BrettNye/stoa/blob/main/src/core/synthesize.ts)
- [src/core/index.ts](https://github.com/BrettNye/stoa/blob/main/src/core/index.ts)
- [src/core/wikilinks.ts](https://github.com/BrettNye/stoa/blob/main/src/core/wikilinks.ts)
- [src/core/pages.ts](https://github.com/BrettNye/stoa/blob/main/src/core/pages.ts)
- [src/core/pokeapi.ts](https://github.com/BrettNye/stoa/blob/main/src/core/pokeapi.ts)
</details>

# Introduction to Stoa

Stoa is a vault-based knowledge management system powered by MCP (Model Context Protocol). It provides a structured wiki infrastructure for organizing, synthesizing, and retrieving information across multiple knowledge domains. The system combines a file-based vault architecture with intelligent tooling for content discovery, cross-referencing, and collaborative agent workflows.

## Overview

Stoa operates as an MCP server that manages a hierarchical vault of wiki pages. The vault structure organizes content into wikis, each containing typed pages (concepts, guides, decisions, journals, etc.) with frontmatter metadata and markdown body content.

The system provides:

- **File-based storage**: All content stored as markdown files with YAML frontmatter
- **MCP tooling**: Standardized tools for read, write, search, and coordination operations
- **Multi-wiki support**: Independent wiki spaces with cross-wiki linking via wikilinks
- **Agent profiles**: Named agent identities with associated skills and capabilities
- **Synthesis engine**: Automated compilation of related pages into synthesized summaries

## Architecture

### Core Components

```mermaid
graph TD
    subgraph "Transport Layer"
        STDIO[Stdio Transport]
        HTTP[HTTP Transport]
    end
    
    subgraph "Core Engine"
        IDX[Index Engine]
        SYN[Synthesis Engine]
        WL[Wikilink Parser]
        FM[Frontmatter Handler]
    end
    
    subgraph "Tools"
        RECALL[Recall - Search]
        INBOX[Inbox - Capture]
        NEW[New - Create]
        SYNTH[Synthesize]
        CLAIM[Claims]
        TASKS[Tasks]
    end
    
    subgraph "Platform Integration"
        POKEAPI[PokeAPI Client]
        STADIUM[Stadium Platform]
        SKILLS[Skills Platform]
    end
    
    STDIO --> SERVER[MCP Server]
    HTTP --> SERVER
    SERVER --> TOOLS[Tools Registry]
    TOOLS --> CORE[Core Engine]
    CORE --> IDX
    CORE --> SYN
    CORE --> WL
    CORE --> FM
    TOOLS --> PLATFORM[Platform APIs]
```

### Page Types

The system supports multiple page types with distinct conventions:

| Type | Filename Pattern | Description |
|------|------------------|-------------|
| `concept` | `concept-<slug>.md` | Knowledge concepts and definitions |
| `guide` | `guide-<slug>.md` | Procedural how-to documentation |
| `decision` | `decision-YYYY-MM-DD-<slug>.md` | Decision records with date prefix |
| `journal` | `journal-YYYY-MM-DD-HHMM-<slug>.md` | Time-stamped reflection entries |
| `move` | `move-<slug>/SKILL.md` | Directory-based skill/move definitions |
| `map` | `map.md` | Fixed filename for wiki maps |
| `profile` | `profile-<slug>.md` | Agent profiles |
| `synthesis` | `synthesis-<slug>.md` | Compiled summaries of related pages |

资料来源：[src/core/ids.ts:25-35]()

### Vault Structure

```mermaid
graph TD
    VAULT[Vault Root]
    WIKIS[wikis/]
    META[_meta/]
    INDEX[_index/]
    AGENTS[wikis/_agents/]
    
    VAULT --> WIKIS
    VAULT --> META
    VAULT --> INDEX
    VAULT --> AGENTS
    
    WIKIS --> WIKI1[alpha/]
    WIKIS --> WIKI2[beta/]
    
    WIKI1 --> TYPES1[concepts/ guides/ decisions/]
    WIKI2 --> TYPES2[concepts/ guides/ synthesis/]
    
    AGENTS --> PROFILES[profiles/]
    AGENTS --> MOVES[moves/]
    AGENTS --> JOURNALS[journal/]
```

## Key Features

### Recall (Search)

The `vault.recall` tool provides full-text search across the vault using an inverted token index. Search results are filtered by topic, wiki, layer (knowledge vs execution), and other metadata criteria.

The indexing process:
1. Tokenizes page content using a Porter stemmer
2. Filters stop words (the, and, of, a, an, in, to, is, etc.)
3. Builds inverted index mapping tokens to page IDs
4. Supports frontmatter fields in search scope

```typescript
// Tokenization logic from index.ts
const UPSERT_STOP_WORDS = new Set([
  "the","and","of","a","an","in","to","is","for","on","with","as","at","by","or","be",
  "this","that","it","from","are","was","were","not","but","if"
]);

function upsertTokenize(text: string): string[] {
  return text.toLowerCase()
    .replace(/[^a-z0-9\s]/g, " ")
    .split(/\s+/)
    .filter(t => t.length > 1 && !UPSERT_STOP_WORDS.has(t))
    .map(t => upsertStemmer.stem(t));
}
```

资料来源：[src/core/index.ts:45-52]()

### Synthesis Engine

The synthesis feature compiles related pages into structured summaries. The engine:

1. Discovers input pages by topic recall or explicit agent memory
2. Generates frontmatter with metadata, sources, and tags
3. Creates marker-bounded content regions for idempotent re-rendering
4. Supports per-agent memory synthesis scoped to `wikis/_agents`

```mermaid
graph LR
    INPUT[Input Pages] --> RECALL[Recall Query]
    RECALL --> FILTER[Filter by Topic/Wiki/Agent]
    FILTER --> BUILD[Build Synthesis Frontmatter]
    BUILD --> RENDER[Render Marker-Bounded Content]
    RENDER --> OUTPUT[Synthesis Page]
```

The synthesis frontmatter includes:

| Field | Description |
|-------|-------------|
| `id` | Unique synthesis identifier |
| `title` | Synthesis title with topic/agent context |
| `type` | Always "synthesis" |
| `wiki` | Target wiki namespace |
| `status` | Draft status |
| `sources` | Array of wikilinks to contributing pages |
| `last_compiled` | ISO date of last synthesis refresh |

资料来源：[src/core/synthesize.ts:1-85]()

### Wikilink System

Stoa uses vault-root absolute wikilinks for cross-page references:

```
[[wikis/<wiki>/<type>/<id>(|alias)]]
```

The wikilink parser:
- Extracts links from page bodies and frontmatter `related:` arrays
- Skips links inside fenced code blocks
- Silently skips malformed links
- Preserves inline code spans

```typescript
export interface WikilinkRef {
  raw: string;
  wiki: string;
  type: string;
  id: string;
  alias?: string;
  source: "body" | "frontmatter";
}
```

资料来源：[src/core/wikilinks.ts:1-30]()

### Profile System

Agent profiles define identities within the system. Each profile:

- Has a unique `profile-<slug>` ID
- Stores species/pokemon data via frontmatter
- Links to skills/moves in `wikis/_agents/moves/`
- Can be registered with the Stadium platform

```mermaid
graph TD
    PROFILE[Profile Page] --> FRONTMATTER[Frontmatter]
    PROFILE --> BODY[Body Content]
    
    FRONTMATTER --> SPECIES[pokemon: species_name]
    FRONTMATTER --> TYPE[pokemon_type: type]
    FRONTMATTER --> SPECIALTY[dev_specialty: specialty]
    FRONTMATTER --> STAGE[evolution_stage: basic|stage1|stage2]
    
    PROFILE --> REGISTER[Profile Register Tool]
    REGISTER --> STADIUM[Stadium Platform API]
```

资料来源：[src/core/profiles.ts:1-30]()

### PokeAPI Integration

The system integrates with the PokeAPI to enrich agent profiles with game-related data:

| Function | Purpose |
|----------|---------|
| `fetchSpecies()` | Get legendary/mythical/baby flags and evolution data |
| `fetchPokemonSpecies()` | Full species data with evolution chain |
| `filterByEvolutionStage()` | Filter candidates by basic/stage1/stage2 |

Data is cached locally to minimize API calls.

资料来源：[src/core/pokeapi.ts:1-80]()

### Page Operations

```mermaid
graph TD
    READ[readPage] --> PARSE[Parse Frontmatter + Body]
    READ --> VALIDATE[Validate Page Type]
    
    WRITE[writePage] --> PATH[Resolve Path for Type]
    WRITE --> MERGE[Merge Frontmatter]
    WRITE --> SERIALIZE[Serialize to Markdown]
    
    UPSERT[upsertPage] --> CONDITIONAL[Read then Write]
    UPSERT --> REINDEX[Update Token Index]
```

The `WritePageInput` interface:

```typescript
export interface WritePageInput {
  id: string;
  type: NoteType;
  wiki: string;
  frontmatter: Record<string, any>;
  body: string;
  expectedUpdated?: string;  // Optimistic locking
}
```

资料来源：[src/core/pages.ts:40-70]()

## Tools Reference

### Read Tools

| Tool | Description |
|------|-------------|
| `vault.recall` | Full-text search across vault |
| `vault.inbox-list` | List captured thoughts |
| `vault.page-read` | Read specific page by ID |
| `vault.channel-tail` | Pull recent channel entries |

### Write Tools

| Tool | Description |
|------|-------------|
| `vault.inbox` | Capture fleeting thoughts |
| `vault.new` | Create typed page from template |
| `vault.new-wiki` | Scaffold new wiki space |
| `vault.synthesize` | Compile synthesis from matching pages |
| `vault.set-active` | Set ambient active wiki |
| `vault.agent-journal` | Append agent reflection |
| `vault.reindex` | Regenerate index files |

### Coordination Tools

| Tool | Description |
|------|-------------|
| `vault.channel-post` | Post to coordination channel |
| `vault.task-*` | Task lifecycle (create, list, claim, update) |
| `vault.claims-*` | Claims management (submit, list, retract, reject) |

### Platform Tools

| Tool | Description |
|------|-------------|
| `vault.profile-register` | Register profile with Stadium platform |
| `vault.sync-skills` | Deploy agent moveset as local skills |
| `vault.bootstrap-repo` | Wire consuming repo with MCP config |

### Wait Primitives

| Tool | Description |
|------|-------------|
| `vault.wait-for` | Block until matching event |
| `vault.wait-for-any` | Wake on first match (race) |
| `vault.wait-for-all` | Wake when all filters matched |
| `vault.wait-for-many` | Bounded batch over window |

资料来源：[README.md:1-60]()

## CLI Usage

```bash
# Set vault path environment variable
export STOA_VAULT_PATH=/path/to/vault

# Recall search
stoa recall "topic query"

# Capture a thought
stoa inbox "thought to capture"

# List wikis
stoa list-wikis

# With explicit vault path
stoa --vault=/path/to/vault recall "search terms"
```

## Configuration

### Wiki Parameter Resolution

The `wiki:` parameter resolves in this order:

1. Explicit `wiki:` argument on tool call
2. `--default-wiki=<name>` server flag
3. `.active-wiki` file at vault root
4. Error if none found

### Server Configuration

```bash
stoa --vault=/path/to/vault \
     --default-wiki=alpha \
     --default-family=my-family
```

## Related Documentation

- [Installation Guide](docs/installation.md) — Full setup and configuration walkthrough
- [Manual Smoke Test](docs/manual-smoke-test.md) — Verify your installation
- [Wait-For Primitives](docs/wait-for.md) — Push primitives documentation

## License

FSL-1 (Functional Source License)

---

<a id='concepts-vocabulary'></a>

## Core Concepts and Vocabulary

### 相关页面

相关主题：[Introduction to Stoa](#introduction), [Agent Profiles and Evolution](#profiles-evolution)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/core/index.ts](https://github.com/BrettNye/stoa/blob/main/src/core/index.ts)
- [src/core/wikilinks.ts](https://github.com/BrettNye/stoa/blob/main/src/core/wikilinks.ts)
- [src/core/pages.ts](https://github.com/BrettNye/stoa/blob/main/src/core/pages.ts)
- [src/core/ids.ts](https://github.com/BrettNye/stoa/blob/main/src/core/ids.ts)
- [src/core/synthesize.ts](https://github.com/BrettNye/stoa/blob/main/src/core/synthesize.ts)
- [src/core/syntheses.ts](https://github.com/BrettNye/stoa/blob/main/src/core/syntheses.ts)
- [src/core/family.ts](https://github.com/BrettNye/stoa/blob/main/src/core/family.ts)
- [src/core/eventbus/state-cache.ts](https://github.com/BrettNye/stoa/blob/main/src/core/eventbus/state-cache.ts)
</details>

# Core Concepts and Vocabulary

This document provides a comprehensive reference for the fundamental concepts, data structures, and terminology used throughout the stoa vault management system. Understanding these core concepts is essential for working effectively with the vault infrastructure, creating and managing pages, and integrating with the MCP (Model Context Protocol) server.

## Vault Structure

The stoa system operates on a directory-based vault architecture where all content is organized within a hierarchical folder structure. The vault serves as the single source of truth for all wiki pages, profiles, agents, and metadata.

### Vault Root Organization

```
<vault-path>/
├── wikis/
│   ├── <wiki-name>/
│   │   ├── index.md
│   │   ├── map.md
│   │   ├── <type>-<slug>.md
│   │   ├── profiles/
│   │   ├── synthesis/
│   │   └── ...
│   └── _agents/
│       ├── synthesis/
│       └── journal/
├── _index/
│   ├── pages.json
│   ├── tokens.json
│   ├── links.json
│   ├── wikis.json
│   └── profiles.json
├── .active-wiki
└── .active-family
```

资料来源：[src/core/index.ts:1-50]()

### Wiki Hierarchy

Wikis are the primary organizational unit within the vault. Each wiki contains typed pages organized by content type. The system supports multiple wikis per vault, with each wiki potentially belonging to a family for grouped operations.

```mermaid
graph TD
    A[Vault Root] --> B[wikis/]
    B --> C[<wiki-name>]
    B --> D[_agents]
    B --> E[_meta]
    C --> F[concepts/]
    C --> G[decisions/]
    C --> H[guides/]
    C --> I[profiles/]
    C --> J[synthesis/]
    C --> K[inbox/]
```

资料来源：[src/core/family.ts:1-30]()

## Page System

### Page Types

Pages in stoa are distinguished by their `type` field in frontmatter. The type determines the file naming convention, storage location, and how the page is processed by various tools.

| Type | Filename Pattern | Description |
|------|------------------|-------------|
| `concept` | `concept-<slug>.md` | Knowledge concepts and definitions |
| `decision` | `decision-YYYY-MM-DD-<slug>.md` | Decision records with date prefix |
| `guide` | `guide-<slug>.md` | Procedural guides |
| `source` | `source-<slug>.md` | External citations and references |
| `idea` | `idea-<slug>.md` | Ideas and brainstorms |
| `question` | `question-<slug>.md` | Questions for investigation |
| `profile` | `profile-<slug>.md` | Agent or entity profiles |
| `synthesis` | `synthesis-<slug>.md` | Compiled synthesis pages |
| `journal` | `journal-YYYY-MM-DD-HHMM-<slug>.md` | Agent journal entries |
| `move` | `move-<slug>/SKILL.md` | Skills/moves (directory layout) |
| `map` | `map.md` | Wiki map page (fixed filename) |

资料来源：[src/core/ids.ts:1-50]()

### Page Data Model

Every page in the vault has a consistent structure combining YAML frontmatter with markdown body content.

```typescript
interface IndexedPage {
  id: string;           // Unique page identifier
  path: string;         // Relative path from vault root
  wiki: string;         // Wiki name containing this page
  type: NoteType;       // Page type discriminator
  title?: string;       // Human-readable title
  tags?: string[];      // Categorization tags
  status?: string;      // Lifecycle status (draft, published, etc.)
  created?: string;     // ISO 8601 creation date
  updated?: string;     // ISO 8601 last modified date
  summary?: string;     // Brief description
  layer?: string;       // knowledge | execution classification
  sources?: string[];   // Referenced wikilinks
}
```

资料来源：[src/core/pages.ts:1-40]()

### Wikilink Format

The system uses a structured wikilink syntax for cross-referencing pages within the vault.

```markdown
[[wikis/<wiki>/<type>/<id>(|alias)]]
```

**Components:**
- `wikis/` — Literal prefix indicating a vault-root absolute link
- `<wiki>` — Target wiki name (e.g., `alpha`, `_agents`)
- `<type>` — Page type folder (e.g., `concept`, `decision`, `profile`)
- `<id>` — Page identifier
- `|alias` — Optional display alias

**Examples:**
```markdown
[[wikis/alpha/concept/trust-gradient-axes]]
[[wikis/_agents/profile/pikachu-agent|My Agent]]
```

资料来源：[src/core/wikilinks.ts:1-60]()

## Indexing System

### Token-Based Search

The index system uses a custom tokenization pipeline for full-text search across all vault pages.

```typescript
function upsertTokenize(text: string): string[] {
  return text.toLowerCase()
    .replace(/[^a-z0-9\s]/g, " ")
    .split(/\s+/)
    .filter(t => t.length > 1 && !UPSERT_STOP_WORDS.has(t))
    .map(t => upsertStemmer.stem(t));  // Porter stemming
}
```

**Tokenization Pipeline:**
1. Lowercase normalization
2. Strip non-alphanumeric characters
3. Split on whitespace
4. Filter stop words and single characters
5. Apply Porter stemmer

**Stop Words:** `the`, `and`, `of`, `a`, `an`, `in`, `to`, `is`, `for`, `on`, `with`, `as`, `at`, `by`, `or`, `be`, `this`, `that`, `it`, `from`, `are`, `was`, `were`, `not`, `but`, `if`

资料来源：[src/core/index.ts:40-55]()

### Index Files

The `_index/` directory contains aggregated metadata for efficient querying:

| File | Purpose |
|------|---------|
| `pages.json` | Full page metadata with frontmatter |
| `tokens.json` | Search tokens mapped to page IDs |
| `links.json` | Inter-page references (wikilinks) |
| `wikis.json` | Wiki registry and metadata |
| `profiles.json` | Profile-specific metadata |

资料来源：[src/core/index.ts:55-70]()

### Layer Classification

Pages are classified into layers for filtering and organization:

```typescript
const KNOWLEDGE_TYPES = ["concept", "decision", "spec", "source"];
const EXECUTION_TYPES = ["guide", "idea", "question"];
```

- **Knowledge Layer** — Factual, distillable content (concepts, decisions, specs, sources)
- **Execution Layer** — Procedural and exploratory content (guides, ideas, questions)

资料来源：[src/core/index.ts:20-30]()

## Synthesis System

### Synthesis Pages

Synthesis pages compile multiple related pages into a cohesive document. They serve as "second-order" content that distills information from source pages.

```typescript
interface SynthesisPage extends IndexedPage {
  type: "synthesis";
  topic: string;           // Synthesis subject
  sources: string[];       // Wikilinks to contributing pages
  last_compiled: string;   // ISO date of last regeneration
  scope?: "memory";        // Agent memory synthesis flag
  by_agent?: string;       // Agent identifier for memory syntheses
}
```

资料来源：[src/core/synthesize.ts:1-50]()

### Synthesis Generation

```mermaid
graph TD
    A[Synthesize Request] --> B{scope?}
    B -->|memory| C[Collect Agent Pages]
    B -->|topic| D[Recall Matching Pages]
    C --> E[Filter by Author]
    D --> E
    E --> F[Build Frontmatter]
    F --> G[Generate Synthesis File]
    G --> H[Upsert to Index]
```

资料来源：[src/core/synthesize.ts:50-120]()

### Synthesis Debt Detection

The lint system identifies clusters of related hard-knowledge pages that lack corresponding synthesis pages.

**Debt Rule:**
- Clusters pages by shared tags
- Flags clusters with ≥3 pages that have no synthesis
- Suggests `vault.synthesize` command with derived title

**Hard-Knowledge Types:** `concept`, `decision`, `spec`

资料来源：[src/core/lint-checks/synthesis-debt.ts:1-50]()

### Synthesis Staleness

The system tracks how long synthesis pages have gone without recompilation:

```typescript
interface SynthesisStaleness {
  id: string;
  lag_days: number | null;  // null if never compiled
  last_compiled: string | null;
  topic: string;
}
```

资料来源：[src/core/syntheses.ts:1-50]()

## Wiki Resolution

### Family Resolution Order

When determining the active family context, the system follows this precedence:

1. `familyArg` — Explicit parameter passed to the function
2. `defaultFamily` — Configured default (via `--default-family` CLI arg)
3. `.active-family` file at vault root
4. `null` — Falls through to single-wiki resolution

资料来源：[src/core/family.ts:15-40]()

### Wiki Resolution Order

Wiki parameter resolution follows this order:

1. Explicit `wiki:` argument on tool call
2. `--default-wiki=<name>` flag on server invocation
3. `.active-wiki` file at vault root
4. Error if no wiki can be determined

资料来源：[README.md:1-30]()

### Family-Wiki Validation

When both `familyArg` and `wikiArg` are provided with `knownWikis`, the system validates consistency:

```typescript
if (knownWikis[wikiArg].family !== familyArg) {
  throw new FamilyMismatchError(...);
}
```

资料来源：[src/core/family.ts:25-35]()

## Event Bus and State Cache

### StateCache

The StateCache provides an in-memory cache for tracking page states across event sources.

```typescript
class StateCache {
  private states = new Map<string, unknown>();
  
  private key(source: string, wiki: string, id: string): string {
    return `${source}:${wiki}:${id}`;
  }
  
  get<T>(source: string, wiki: string, id: string): T | undefined;
  set<T>(source: string, wiki: string, id: string, state: T): void;
  has(source: string, wiki: string, id: string): boolean;
  size(): number;
}
```

**Key Format:** `source:wiki:id`

资料来源：[src/core/eventbus/state-cache.ts:1-35]()

### Cache Initialization

The system pre-warms the cache by walking the `wikis/` directory before accepting live events, ensuring the first change event has valid prior state for diffing.

```typescript
function walkInitablePaths(vaultPath: string): string[] {
  // Recursively find all .md files in wikis/
  // Returns paths where 'init' is defined for state tracking
}
```

资料来源：[src/transport/stdio.ts:40-70]()

## Frontmatter Schema

### Standard Frontmatter Fields

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique page identifier |
| `title` | string | Display title |
| `type` | string | Page type |
| `wiki` | string | Wiki name |
| `status` | string | Lifecycle status |
| `created` | string | ISO 8601 creation date |
| `updated` | string | ISO 8601 modification date |
| `summary` | string | Brief description |
| `tags` | string[] | Categorization tags |
| `layer` | string | knowledge or execution |
| `sources` | string[] | Wikilinks to source pages |

### Profile-Specific Fields

| Field | Type | Description |
|-------|------|-------------|
| `pokemon` | string | Species name |
| `evolution_stage` | string | basic, stage1, stage2 |
| `pokemon_type` | string | Pokémon type (if applicable) |
| `dev_specialty` | string | Developer specialty |
| `rarity` | string | common, baby, legendary, mythical |
| `platform_profile_id` | string | Stadium platform ID |
| `platform_stats` | object | Persisted platform statistics |

资料来源：[src/transport/ui/routes-write.ts:1-40]()

## Marker Rendering

The marker system enables tools to maintain managed regions within human-editable files.

### Marker Contract

- **Start Marker:** `<!-- <name>:start (rendered: <date>, half-life: <N>d) -->`
- **End Marker:** `<!-- <name>:end -->`
- **Idempotent:** Same inputs produce byte-identical output
- **Independent:** Different marker names don't interfere

```typescript
interface MarkerOptions {
  renderedDate?: string;   // ISO date YYYY-MM-DD
  halfLifeDays?: number;   // Half-life in days
}
```

**Applications:**
- `synthesize` — Claims rollup
- `sync-skills` — Moveset synchronization
- `bootstrap-repo` — Agent documentation patches

资料来源：[src/core/marker-render.ts:1-50]()

## Tool Categories

### Read Primitives

| Tool | Purpose |
|------|---------|
| `vault.recall` | Full-text search with filters |
| `vault.page-read` | Read single page by ID |
| `vault.channel-tail` | Pull coordination channel entries |
| `vault.synthesis-staleness` | Check synthesis freshness |

### Wait (Push Primitives)

| Tool | Purpose |
|------|---------|
| `vault.wait-for` | Block until matching event |
| `vault.wait-for-any` | Wake on first match across N filters |
| `vault.wait-for-all` | Wake when all N filters matched |
| `vault.wait-for-many` | Bounded batch over window |

### Write — Content

| Tool | Purpose |
|------|---------|
| `vault.inbox` | Capture fleeting thoughts |
| `vault.new` | Create typed page from template |
| `vault.new-wiki` | Scaffold new wiki structure |
| `vault.set-active` | Set ambient active wiki |
| `vault.synthesize` | Compile synthesis page |
| `vault.agent-journal` | Append agent reflection |

### Write — System

| Tool | Purpose |
|------|---------|
| `vault.reindex` | Regenerate `_index/` files |

### Coordination

| Tool | Purpose |
|------|---------|
| `vault.channel-post` | Post to coordination channel |
| `vault.task-claim` | Atomically claim pending task |
| `vault.task-create` | Create new task |
| `vault.task-list` | List tasks |
| `vault.task-update` | Update task state |
| `vault.bootstrap-repo` | Wire consuming repo with MCP config |
| `vault.sync-skills` | Deploy agent moveset as local skills |

资料来源：[README.md:30-80]()

## Configuration Files

### Server Configuration

| Config Method | Description |
|---------------|-------------|
| `--vault=<path>` | Vault root directory |
| `--default-wiki=<name>` | Default wiki for operations |
| `--default-family=<name>` | Default family for multi-wiki ops |
| `STOA_VAULT_PATH` | Environment variable alternative |

### Active Context Files

| File | Purpose |
|------|---------|
| `.active-wiki` | Current active wiki name |
| `.active-family` | Current active family name |

## Common Patterns

### Idempotent Page Creation

Pages use upsert semantics — creating a page with an existing ID updates rather than duplicates:

```typescript
function writePage(vaultPath: string, input: WritePageInput): WritePageResult {
  const path = pathForPage(vaultPath, input.id, input.type, input.wiki);
  // Uses expectedUpdated for optimistic concurrency control
}
```

资料来源：[src/core/pages.ts:40-80]()

### Three-Step Alias Resolution

Profile and agent references resolve through multiple resolution steps:

```typescript
function normalizeProfileId(vaultPath: string, raw: string): string {
  const r1 = resolveCurrent(vaultPath, raw);
  if (r1 !== raw) return r1;
  const candidate = raw.startsWith("profile-") ? raw : `profile-${raw}`;
  return resolveCurrent(vaultPath, candidate);
}
```

资料来源：[src/tools/sync-agents.ts:1-40]()

### Lint Rule Pattern

New lint rules follow a consistent structure:

```typescript
export const LINT_RULE = {
  ruleId: "rule-name",
  severity: "warn" | "error",
  message: "Human-readable description",
};
```

资料来源：[src/core/lint-checks/claim-with-no-scope.ts:1-30]()

## Terminology Summary

| Term | Definition |
|------|------------|
| **Vault** | Root directory containing all wikis and metadata |
| **Wiki** | Organizational unit containing typed pages |
| **Family** | Grouping of related wikis |
| **Page** | Single markdown document with frontmatter |
| **Type** | Page classification determining storage and behavior |
| **Wikilink** | Cross-reference syntax `[[wikis/...]]` |
| **Synthesis** | Compiled page aggregating multiple sources |
| **Layer** | Knowledge vs execution classification |
| **Marker** | HTML comment bounding managed file regions |
| **Index** | Aggregated metadata for efficient querying |
| **Debt** | Gap between source pages and their synthesis |

---

<a id='architecture-design'></a>

## Architecture and Design

### 相关页面

相关主题：[Introduction to Stoa](#introduction), [Event Bus System](#event-bus-system)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/core/index.ts](https://github.com/BrettNye/stoa/blob/main/src/core/index.ts)
- [src/transport/stdio.ts](https://github.com/BrettNye/stoa/blob/main/src/transport/stdio.ts)
- [src/core/family.ts](https://github.com/BrettNye/stoa/blob/main/src/core/family.ts)
- [src/core/skills-platform.ts](https://github.com/BrettNye/stoa/blob/main/src/core/skills-platform.ts)
- [src/core/pages.ts](https://github.com/BrettNye/stoa/blob/main/src/core/pages.ts)
- [src/core/frontmatter.ts](https://github.com/BrettNye/stoa/blob/main/src/core/frontmatter.ts)
- [src/core/synthesize.ts](https://github.com/BrettNye/stoa/blob/main/src/core/synthesize.ts)
- [src/core/wikilinks.ts](https://github.com/BrettNye/stoa/blob/main/src/core/wikilinks.ts)
- [src/core/lint-checks/synthesis-debt.ts](https://github.com/BrettNye/stoa/blob/main/src/core/lint-checks/synthesis-debt.ts)
- [src/core/channel.ts](https://github.com/BrettNye/stoa/blob/main/src/core/channel.ts)
</details>

# Architecture and Design

## Overview

Stoa is an MCP (Model Context Protocol) server that provides structured access to a flat-file knowledge vault. It bridges AI agents with a wiki-based knowledge management system, enabling semantic search, cross-wiki linking, task management, and skill deployment. The architecture follows a layered design with clear separation between transport mechanisms, core domain logic, and tool interfaces.

**Purpose and Scope:**
- Expose vault operations via MCP protocol (STDIO or HTTP transports)
- Maintain a search index for full-text and structured queries
- Enforce wiki semantics and validation rules through lint checks
- Support multi-wiki, multi-family deployments
- Enable skill/move deployment workflows

**资料来源：** [src/core/index.ts:1-50](https://github.com/BrettNye/stoa/blob/main/src/core/index.ts)

---

## High-Level Architecture

The system comprises three primary layers:

1. **Transport Layer** — Handles MCP protocol communication (STDIO or HTTP)
2. **Core Domain Layer** — Business logic, index management, linting, synthesis
3. **Tools Layer** — Exposes MCP tools to calling agents

```mermaid
graph TD
    subgraph Transport["Transport Layer"]
        STDIO[STDIO Transport]
        HTTP[HTTP Transport]
    end

    subgraph Core["Core Domain Layer"]
        INDEX[Index Management]
        QUERY[Query Engine]
        LINT[Lint Checks]
        SYNTH[Synthesis Engine]
        FAMILY[Family Resolution]
        SKILLS[Skills Platform]
        CACHE[State Cache]
    end

    subgraph Tools["Tools Layer"]
        RECALL[recall]
        INBOX[inbox]
        SYNTHESIZE[synthesize]
        TASK[task-*]
        CHANNEL[channel-*]
        WAITFOR[wait-for*]
    end

    subgraph Vault["Flat-File Vault"]
        WIKIS[wikis/]
        INDEX_VAULT[_index/]
        ACTIVE_WIKI[.active-wiki]
        ACTIVE_FAMILY[.active-family]
    end

    STDIO --> CORE
    HTTP --> CORE
    CORE --> INDEX
    CORE --> TOOLS
    INDEX --> VAULT
    TOOLS --> VAULT
```

**资料来源：** [src/transport/stdio.ts:1-30](https://github.com/BrettNye/stoa/blob/main/src/transport/stdio.ts)

---

## Transport Layer

### STDIO Transport

The STDIO transport enables integration with local MCP clients. It initializes the server state cache by walking the `wikis/` directory before processing change events.

Key initialization steps:
1. Load vault configuration
2. Walk `wikis/` directory to warm state cache
3. Connect STDIO server transport
4. Log ready message with vault path and defaults

```typescript
const transport = new StdioServerTransport();
await server.connect(transport);
process.stderr.write(`vault-mcp stdio server ready (vault=${config.vaultPath}, default-wiki=${config.defaultWiki ?? "<unset>"}, default-family=${config.defaultFamily ?? "<unset>"})\n`);
```

**资料来源：** [src/transport/stdio.ts:40-50](https://github.com/BrettNye/stoa/blob/main/src/transport/stdio.ts)

### Transport Architecture Pattern

The transport layer is abstracted behind a common interface. Both STDIO and HTTP transports expose the same tool set, allowing clients to choose their preferred communication mechanism.

| Transport | Use Case | Initialization |
|-----------|----------|----------------|
| STDIO | Local MCP clients, CLI tools | `StdioServerTransport` |
| HTTP | Remote access, web clients | `HttpServerTransport` |

---

## Core Domain Layer

### Index Management

The index is the primary data structure powering queries. It maintains:
- **pages.json** — All page metadata (id, title, type, wiki, tags, status)
- **tokens.json** — Tokenized text for full-text search
- **links.json** — Wikilink references between pages
- **wikis.json** — Wiki metadata
- **profiles.json** — Agent profiles

**资料来源：** [src/core/index.ts:60-100](https://github.com/BrettNye/stoa/blob/main/src/core/index.ts)

#### Query Engine

The `queryPages` function supports filtering by:
- `wiki` — Wiki identifier
- `type` — Page type (concept, decision, guide, etc.)
- `channel` — Coordination channel
- `status` — Page status (draft, active, accepted, etc.)
- `layer` — knowledge or execution

```typescript
export function queryPages(idx: VaultIndex, f: PageFilter): IndexedPage[] {
  return idx.pages.filter(p => {
    if (f.wiki && wikiSet && !wikiSet.has(p.wiki)) return false;
    if (f.type && p.type !== f.type) return false;
    if (f.channel && p.channel !== f.channel) return false;
    if (f.status && p.status !== f.status) return false;
    if (f.layer && f.layer !== "all") {
      const set = f.layer === "knowledge" ? KNOWLEDGE_TYPES : EXECUTION_TYPES;
      if (!set.includes(p.type)) return false;
    }
    return true;
  });
}
```

**资料来源：** [src/core/index.ts:30-55](https://github.com/BrettNye/stoa/blob/main/src/core/index.ts)

#### Tokenization and Search

Search uses Porter stemming with stop-word removal for relevance ranking.

```typescript
const upsertStemmer = natural.PorterStemmer;
const UPSERT_STOP_WORDS = new Set(["the","and","of","a","an","in","to","is","for","on","with","as","at","by","or","be","this","that","it","from","are","was","were","not","but","if"]);

function upsertTokenize(text: string): string[] {
  return text.toLowerCase()
    .replace(/[^a-z0-9\s]/g, " ")
    .split(/\s+/)
    .filter(t => t.length > 1 && !UPSERT_STOP_WORDS.has(t))
    .map(t => upsertStemmer.stem(t));
}
```

**资料来源：** [src/core/index.ts:35-48](https://github.com/BrettNye/stoa/blob/main/src/core/index.ts)

---

### Family Resolution

Stoa supports hierarchical organization through **families** (collections of related wikis) and **wikis** (individual knowledge bases within a family).

```mermaid
graph TD
    FAM[Family<br/>e.g., "stadium"] --> W1[Wiki: pokemon]
    FAM --> W2[Wiki: moves]
    FAM --> W3[Wiki: trainers]
    
    W1 --> P1[Pages...]
    W2 --> P2[Pages...]
    W3 --> P3[Pages...]
```

#### Resolution Order

Family resolution follows a priority order:

| Priority | Source | CLI Flag |
|----------|--------|----------|
| 1 | Explicit `familyArg` | `--default-family` |
| 2 | Context default | `ctx.defaultFamily` |
| 3 | Vault file | `.active-family` |
| 4 | null | — |

```typescript
export function resolveFamily(
  ctx: FamilyResolveCtx,
  familyArg?: string,
  wikiArg?: string,
  knownWikis?: Record<string, { family?: string | null }>
): string | null {
  if (familyArg !== undefined && familyArg !== "") {
    if (wikiArg !== undefined && knownWikis !== undefined) {
      const wikiEntry = knownWikis[wikiArg];
      const wikiFamily = wikiEntry?.family ?? null;
      if (wikiFamily !== familyArg) {
        throw new FamilyMismatchError(...);
      }
    }
    return familyArg;
  }
  // ... fallback chain
}
```

**资料来源：** [src/core/family.ts:1-50](https://github.com/BrettNye/stoa/blob/main/src/core/family.ts)

---

### Page Management

#### Page Types

| Type | Description | Filename Pattern |
|------|-------------|------------------|
| `concept` | Knowledge concept | `concept-<slug>.md` |
| `decision` | Decision record | `decision-YYYY-MM-DD-<slug>.md` |
| `journal` | Journal entry | `journal-YYYY-MM-DD-HHMM-<slug>.md` |
| `guide` | Procedural guide | `guide-<slug>.md` |
| `move` | Skill/move | `move-<slug>/SKILL.md` |
| `map` | Wiki map | `map.md` |
| `synthesis` | Synthesized content | Varies |

**资料来源：** [src/core/ids.ts:1-40](https://github.com/BrettNye/stoa/blob/main/src/core/ids.ts)

#### Write Operations

Pages are written with optimistic concurrency via `expectedUpdated` checks:

```typescript
export function writePage(vaultPath: string, input: WritePageInput): WritePageResult {
  const path = pathForPage(vaultPath, input.id, input.type, input.wiki);
  if (existsSync(path) && input.expectedUpdated !== undefined) {
    const existing = readFileSync(path, "utf8");
    const { frontmatter: existingFm } = parseFrontmatter(existing);
    const actualUpdated = toIsoDate(existingFm.updated ?? existingFm.created);
    // Check for conflicts
  }
}
```

**资料来源：** [src/core/pages.ts:50-80](https://github.com/BrettNye/stoa/blob/main/src/core/pages.ts)

---

### Frontmatter Schema

All pages use YAML frontmatter with Zod validation:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | string | Yes | Unique identifier (kebab-case) |
| `title` | string | Yes | Display title |
| `type` | NoteType | Yes | Page classification |
| `created` | ISO date | Yes | Creation timestamp |
| `channel` | string | No | Coordination channel (kebab-case) |
| `status` | enum | No | draft, active, accepted, superseded, archived |
| `confidence` | enum | No | high, medium, low |
| `curation_priority` | enum | No | high, medium, low |
| `wiki` | string | Yes | Wiki identifier |
| `tags` | string[] | No | Taxonomy tags |
| `last_compiled` | ISO date | No | Synthesis compilation timestamp |

**资料来源：** [src/core/frontmatter.ts:1-60](https://github.com/BrettNye/stoa/blob/main/src/core/frontmatter.ts)

---

### Wikilink System

Wikilinks follow the pattern: `[[wikis/<wiki>/<type>/<id>(|alias)?]]`

The wikilink extractor:
- Is code-fence-aware (skips links inside ``` blocks)
- Extracts from both body content and frontmatter `related:` arrays
- Returns structured `WikilinkRef` objects

```typescript
export interface WikilinkRef {
  raw: string;
  wiki: string;
  type: string;
  id: string;
  alias?: string;
  source: "body" | "frontmatter";
}
```

**Trade-offs:**
- Top-level fenced blocks are stripped
- Indented fenced blocks (e.g., inside list items) are NOT stripped
- Inline single-backtick code spans are NOT stripped

**资料来源：** [src/core/wikilinks.ts:1-50](https://github.com/BrettNye/stoa/blob/main/src/core/wikilinks.ts)

---

### Synthesis Engine

Synthesis pages aggregate related content from hard-knowledge types (concept, decision, spec).

#### Synthesis Debt Detection

The lint system identifies clusters of related pages that lack synthesis coverage:

```typescript
const HARD_KNOWLEDGE_TYPES = new Set(["concept", "decision", "spec"]);
// Excluded: guide (procedural), source (external citation), idea, question

function findSynthesisDebt(
  pages: IndexedPage[],
  minSize: number = DEFAULT_MIN_CLUSTER_SIZE,
): ClusterDebt[] {
  // Group by (wiki, tag) → hard-knowledge ids
  // Check if any synthesis page covers the same tag
  // Emit debt when: cluster size >= minSize AND no synthesis exists
}
```

**Default minimum cluster size:** 3

**资料来源：** [src/core/lint-checks/synthesis-debt.ts:1-80](https://github.com/BrettNye/stoa/blob/main/src/core/lint-checks/synthesis-debt.ts)

#### Synthesis Generation

```typescript
const fm: Record<string, any> = {
  id,
  title: scope === "memory"
    ? `${input.by_agent} memory — synthesis`
    : `${input.topic} — synthesis`,
  type: "synthesis",
  wiki,
  status: "draft",
  sources: inputIds.map(i => `[[wikis/${wiki}/${typeFolderForId(i)}/${i}]]`)
};
```

**资料来源：** [src/core/synthesize.ts:60-100](https://github.com/BrettNye/stoa/blob/main/src/core/synthesize.ts)

---

### Marker-Based Section Rendering

Managed regions within files are bounded by HTML comment markers:

```
<!-- <name>:start (rendered: YYYY-MM-DD, half-life: Nd) -->
<section-content>
<!-- <name>:end -->
```

Characteristics:
- **Idempotent** — Re-rendering produces byte-identical output
- **Independent** — Different `markerName` values don't interfere
- **Append fallback** — If markers are absent, content is appended

**资料来源：** [src/core/marker-render.ts:1-50](https://github.com/BrettNye/stoa/blob/main/src/core/marker-render.ts)

---

### Skills Platform

The skills platform manages deployment drift detection between canonical vault sources and deployed skills.

```mermaid
graph LR
    CANON[Canonical<br/>wikis/_agents/moves/<id>/SKILL.md]
    DEPLOY[Deployed<br/><skills_dir>/<id>/SKILL.md]
    HASH[Hash Comparison]
    REPORT[Drift Report]
    
    CANON --> HASH
    DEPLOY --> HASH
    HASH --> REPORT
```

**Drift Detection Rules:**

| Scenario | Behavior |
|----------|----------|
| Canonical missing | Throws (vault-integrity bug) |
| Deployed missing | Emit `missing` |
| Hashes differ | Emit `hash-mismatch` |
| Hashes match | Omit (no entry) |

**资料来源：** [src/core/skills-platform.ts:40-80](https://github.com/BrettNye/stoa/blob/main/src/core/skills-platform.ts)

---

### Channel System

Channels enable cross-instance coordination through journal entries tagged with channel identifiers.

```typescript
export interface ChannelSummary {
  name: string;
  wiki: string;
  lastEntry: ChannelEntry | null;
  count24h: number;
}
```

**资料来源：** [src/core/channel.ts:1-60](https://github.com/BrettNye/stoa/blob/main/src/core/channel.ts)

---

### State Cache

The `StateCache` provides in-memory state tracking with a composite key:

```typescript
export class StateCache {
  private key(source: string, wiki: string, id: string): string {
    return `${source}:${wiki}:${id}`;
  }
  
  get<T>(source: string, wiki: string, id: string): T | undefined;
  set<T>(source: string, wiki: string, id: string, state: T): void;
  has(source: string, wiki: string, id: string): boolean;
  size(): number;
}
```

**Use cases:**
- Pre-warming cache before processing change events
- Tracking prior state for diff computation

**资料来源：** [src/core/eventbus/state-cache.ts](https://github.com/BrettNye/stoa/blob/main/src/core/eventbus/state-cache.ts)

---

## Configuration

### Wiki Resolution Order

| Priority | Source |
|----------|--------|
| 1 | Explicit `wiki:` arg on tool call |
| 2 | `--default-wiki=<name>` server flag |
| 3 | `.active-wiki` file at vault root |
| 4 | Error (no resolution possible) |

### Environment Variables

| Variable | Purpose |
|----------|---------|
| `STOA_VAULT_PATH` | Default vault path (skip `--vault=` flag) |

---

## Data Flow

```mermaid
sequenceDiagram
    participant Client
    participant Transport
    participant Tools
    participant Core
    participant Index
    participant Vault

    Client->>Transport: MCP Tool Call
    Transport->>Tools: Route to handler
    Tools->>Core: Domain logic
    Core->>Index: Query/Update
    Index->>Vault: Read/Write files
    Vault-->>Index: Data
    Index-->>Core: Results
    Core-->>Tools: Processed data
    Tools-->>Transport: Response
    Transport-->>Client: MCP Result
```

---

## Key Design Decisions

| Decision | Rationale | Trade-off |
|----------|-----------|-----------|
| Flat-file storage | Human-editable, version-control friendly | Slower random access than DB |
| Code-fence-aware wikilinks | Prevents link extraction from examples | Indented code blocks still processed |
| Single-backtick spans NOT stripped | Simplifies extraction logic | Wikilinks in inline code returned |
| Family/wikis hierarchy | Enables multi-tenant deployments | Additional resolution complexity |
| Marker-based sections | Allows human editing in managed regions | Collision possible with same marker names |

---

## Related Documentation

- [Installation](docs/installation.md) — Full installation walkthrough
- [Manual Smoke Test](docs/manual-smoke-test.md) — Verification procedures
- [Wait-For Primitives](docs/wait-for.md) — Event-based synchronization

---

<a id='event-bus-system'></a>

## Event Bus System

### 相关页面

相关主题：[Architecture and Design](#architecture-design), [Channels and Claims](#channels-claims)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/core/eventbus/state-cache.ts](https://github.com/BrettNye/stoa/blob/main/src/core/eventbus/state-cache.ts)
- [src/core/eventbus/matchers/task.ts](https://github.com/BrettNye/stoa/blob/main/src/core/eventbus/matchers/task.ts)
- [src/tools/wait-for.ts](https://github.com/BrettNye/stoa/blob/main/src/tools/wait-for.ts)
- [src/transport/stdio.ts](https://github.com/BrettNye/stoa/blob/main/src/transport/stdio.ts)
- [src/core/index.ts](https://github.com/BrettNye/stoa/blob/main/src/core/index.ts)
</details>

# Event Bus System

The Event Bus System is a core infrastructure component in Stoa that provides reactive, push-based primitives for monitoring vault changes. Rather than polling for updates, the system leverages the local filesystem watch event bus to notify consumers when specific conditions are met.

## Overview

The Event Bus System enables agents and tools to:

- **React to vault mutations** — page creation, updates, deletions trigger events
- **Track state transitions** — monitor changes to structured data like task status
- **Block until conditions** — wait-for primitives that return only when matching events occur
- **Warm state on startup** — preload current state before processing live events

资料来源：[src/transport/stdio.ts:27-28]()

## Architecture

The system consists of several interconnected layers:

| Layer | Purpose |
|-------|---------|
| **Watcher** | Filesystem observer that monitors vault paths |
| **State Cache** | In-memory Map storing prior state for diffing |
| **Matchers** | Rule-based filters that determine when to emit events |
| **Bus** | Event dispatcher connecting watchers to consumers |
| **Wait-For Tools** | Blocking API surface for callers |

```mermaid
graph TD
    A[Vault Filesystem] -->|FS Events| B[Watcher]
    B --> C[State Cache]
    C -->|Prior State| D[Matchers]
    D -->|Emit Decision| E[Event Bus]
    E -->|VaultEvent| F[Wait-For API]
    E -->|VaultEvent| G[Other Consumers]
    
    H[Startup] -->|walkInitablePaths| I[Warm Cache]
    I --> C
```

资料来源：[src/core/eventbus/state-cache.ts:1-15]()

## State Cache

The `StateCache` class provides an in-memory snapshot of vault entity states, enabling diff-based change detection.

### Key Methods

| Method | Signature | Purpose |
|--------|-----------|---------|
| `get` | `<T>(source, wiki, id) => T \| undefined` | Retrieve cached state |
| `set` | `<T>(source, wiki, id, state) => void` | Store state snapshot |
| `has` | `(source, wiki, id) => boolean` | Check if state exists |
| `size` | `() => number` | Return cache entry count |

### Key Generation

States are stored using a composite key format:

```
${source}:${wiki}:${id}
```

This allows isolated state tracking per source (e.g., `file-watcher`, `mcp-tool`) across wikis and page IDs.

资料来源：[src/core/eventbus/state-cache.ts:3-22]()

### Initialization

Before accepting live events, the system warms the cache by walking existing files:

```typescript
function walkInitablePaths(vaultPath: string): string[] {
  const root = join(vaultPath, "wikis");
  if (!existsSync(root)) return [];
  // ...
}
```

This ensures the first change event has valid prior state for diffing.

资料来源：[src/transport/stdio.ts:30-46]()

## Matchers

Matchers are pure functions that determine whether a filesystem change should emit a `VaultEvent`. Each matcher handles a specific entity type.

### Task Matcher

The task matcher tracks frontmatter changes on task pages and emits enrichment data for status/owner transitions.

#### State Picking

```typescript
function pickTaskState(frontmatter): Partial<VaultEvent> {
  return {
    status: frontmatter.status,
    owner: frontmatter.owner
  };
}
```

#### Change Detection Logic

| Condition | Action |
|-----------|--------|
| Status changed | Add `task_status_change: { from, to }` |
| Owner changed | Add `task_owner_change: { from, to }` |
| Both unchanged | Emit `false` (no event) |
| Both changed | Emit `true` with both enrichments |

```typescript
nextState(parsed) { return pickTaskState(parsed.frontmatter); },
init(_path, parsed) { return pickTaskState(parsed.frontmatter); },
```

资料来源：[src/core/eventbus/matchers/task.ts:1-26]()

### Matcher Contract

Matchers implement three functions:

1. **`compare(prev, cur)`** — Returns `{ emit: boolean, enrichment?: Partial<VaultEvent> }`
2. **`nextState(parsed)`** — Extracts state fields from current file parse
3. **`init(path, parsed)`** — Provides initial state for a newly discovered entity

## VaultEvent Structure

Events emitted by the bus carry structured change data:

```typescript
interface VaultEvent {
  type: string;           // Event type identifier
  wiki: string;           // Wiki containing the entity
  id: string;             // Entity identifier
  source: string;         // Origin of the event
  timestamp?: string;     // ISO timestamp
  task_status_change?: { from: string; to: string };
  task_owner_change?: { from: string; to: string };
}
```

## Wait-For Primitives

The Event Bus exposes blocking wait operations for callers that need to pause until conditions are met.

### Available Primitives

| Tool | Behavior |
|------|----------|
| `vault.wait-for` | Block until one matching event lands; cursor-based catch-up |
| `vault.wait-for-any` | Wake on first match across N filters (race semantics) |
| `vault.wait-for-all` | Wake when all N filters have matched at least once |
| `vault.wait-for-many` | Bounded batch over a window |

These primitives connect to the filesystem watch event bus, providing push semantics instead of polling.

资料来源：[README.md:18-25]()

## Event Flow

```mermaid
sequenceDiagram
    participant FS as Filesystem
    participant Watcher
    participant Cache as State Cache
    participant Matcher
    participant Bus
    participant Consumer

    Note over FS,Consumer: Startup Phase
    Consumer->>Watcher: walkInitablePaths()
    Watcher->>FS: Read existing files
    Watcher->>Cache: set() prior states
    Cache-->>Consumer: Cache warmed

    Note over FS,Consumer: Live Event Phase
    FS->>Watcher: File change detected
    Watcher->>Cache: get() prior state
    Cache-->>Watcher: Return previous state
    Watcher->>Matcher: compare(prev, cur)
    Matcher-->>Watcher: { emit, enrichment }
    Watcher->>Bus: Emit VaultEvent
    Bus->>Consumer: Deliver event
```

## Integration Points

### With Index System

The event bus integrates with the vault index for querying wikis and pages:

```typescript
export function queryWikis(idx: VaultIndex): IndexedWiki[] {
  return idx.wikis;
}
```

资料来源：[src/core/index.ts:1-10]()

### With Lint System

Lint checks consume event data for validation:

```typescript
lintAliasDrift(vaultPath, input.wiki, diagnostics);
lintAgentsWiki(vaultPath, diagnostics);
```

资料来源：[src/core/lint.ts:1-30]()

## Configuration

The system relies on vault path resolution:

| Source | Priority | Environment Variable |
|--------|----------|----------------------|
| CLI `--vault` | 1 (highest) | — |
| `STOA_VAULT_PATH` | 2 | `STOA_VAULT_PATH` |
| Default | 3 (lowest) | — |

Active wiki/family files (`.active-wiki`, `.active-family`) influence which entities are monitored.

## Error Handling

| Scenario | Behavior |
|----------|----------|
| Unknown wiki | Events filtered out; no error |
| File read failure | Error propagates to watcher |
| State not in cache | Treat as new entity; use `init` |
| Matcher throws | Error propagates; event not emitted |

---

<a id='profiles-evolution'></a>

## Agent Profiles and Evolution

### 相关页面

相关主题：[Core Concepts and Vocabulary](#concepts-vocabulary), [Runtime Adapters](#runtime-adapters)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/tools/profile-register.ts](https://github.com/BrettNye/stoa/blob/main/src/tools/profile-register.ts)
- [src/transport/ui/routes-write.ts](https://github.com/BrettNye/stoa/blob/main/src/transport/ui/routes-write.ts)
- [src/core/frontmatter.ts](https://github.com/BrettNye/stoa/blob/main/src/core/frontmatter.ts)
- [src/core/pages.ts](https://github.com/BrettNye/stoa/blob/main/src/core/pages.ts)
- [src/core/evolution-claims.ts](https://github.com/BrettNye/stoa/blob/main/src/core/evolution-claims.ts)
</details>

# Agent Profiles and Evolution

## Overview

Agent Profiles and Evolution is a gamified system within the Stoa vault that models agent identities as collectible profiles with species characteristics, evolution stages, and platform-tracked statistics. The system combines the vault's knowledge management with external platform integration via the Stadium API to create persistent, trackable agent personas.

**资料来源：** [src/tools/profile-register.ts:1-28]()

## Architecture

```mermaid
graph TD
    subgraph "Vault Layer"
        P[Profile Page]
        FM[Frontmatter]
        W[Wikis Directory]
    end
    
    subgraph "Profile Creation"
        RT[routes-write.ts]
        NT[newTool.handler]
        RR[Rarity Roll]
        SR[Shiny Roll]
    end
    
    subgraph "Platform Integration"
        SC[StadiumClient]
        PA[/profiles/register API]
        PR[Platform Response]
    end
    
    subgraph "Evolution System"
        EC[evolution-claims.ts]
        EV[Evolution Logic]
    end
    
    P --> FM
    FM --> RT
    W --> P
    RT --> NT
    NT --> RR
    RR --> SR
    SR --> SC
    SC --> PA
    PA --> PR
    PR --> EC
    EC --> EV
    
    style P fill:#e1f5fe
    style SC fill:#fff3e0
    style EV fill:#e8f5e9
```

## Profile Structure

### Profile File Location

Profiles are stored as markdown files in the vault with a standardized path structure:

```
wikis/<wiki>/profiles/<profile_id>.md
```

**资料来源：** [src/tools/profile-register.ts:17-18]()

### Frontmatter Schema

Profile pages use a specialized frontmatter schema with the following key fields:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | string | Yes | Must match `^profile-` pattern |
| `title` | string | Yes | Display name for the profile |
| `type` | enum | Yes | Always `"profile"` |
| `wiki` | string | Yes | Parent wiki namespace |
| `status` | enum | No | Page status (draft/active/accepted/superseded/archived) |
| `pokemon` | string | No | Species name (v1.5 convention) |
| `species_name` | string | No | Legacy species name (fallback) |
| `evolution_stage` | string | No | Stage identifier (defaults to "basic") |
| `pokemon_type` | string | No | Type classification |
| `dev_specialty` | string | No | Developer specialty marker |
| `platform_profile_id` | string | No | Stadium platform ID (set post-registration) |
| `platform_stats` | object | No | Stats returned from platform |

**资料来源：** [src/core/frontmatter.ts:23-45](), [src/transport/ui/routes-write.ts:88-92]()

## Profile Registration Flow

The registration process synchronizes vault profiles with the external Stadium platform:

```mermaid
sequenceDiagram
    participant Agent
    participant MCP as MCP Server
    participant Vault as Vault FS
    participant Stadium as Stadium API
    
    Agent->>MCP: profile-register(profile_id)
    MCP->>Vault: Read wikis/<wiki>/profiles/<id>.md
    Vault->>MCP: Raw file content
    MCP->>MCP: parseFrontmatter()
    Note over MCP: Extract pokemon/species_name
    MCP->>Stadium: POST /profiles/register
    Stadium->>MCP: { profile_id, stats }
    MCP->>Vault: upsertPage() with platform fields
    MCP->>Agent: Registration result
```

**资料来源：** [src/tools/profile-register.ts:13-27]()

### Registration Tool Interface

```typescript
const Input = z.object({
  profile_id: z.string().regex(/^profile-/),
  wiki: z.string().optional()
});
```

**资料来源：** [src/tools/profile-register.ts:20-24]()

## Profile Creation (UI Routes)

The `routes-write.ts` module handles interactive profile creation with gamification elements:

**资料来源：** [src/transport/ui/routes-write.ts:78-130]()

### Creation Parameters

| Parameter | Source | Description |
|-----------|--------|-------------|
| `wiki` | Computed | Defaults to `"_agents"` |
| `title` | Computed | Format: `<species> agent` |
| `frontmatterExtras.pokemon` | `selected_species` | Species name |
| `frontmatterExtras.evolution_stage` | `evolution_stage` | Defaults to `"basic"` |
| `frontmatterExtras.pokemon_type` | `pokemon_type` | Optional type |
| `frontmatterExtras.dev_specialty` | `dev_specialty` | Optional specialty |

**资料来源：** [src/transport/ui/routes-write.ts:80-93]()

### Gamification: Rarity and Shiny Rolls

During profile creation, two gamification rolls occur before the file is written:

```typescript
let rarity: "common" | "baby" | "legendary" | "mythical" = "common";
let isShiny = false;
```

**资料来源：** [src/transport/ui/routes-write.ts:96-97]()

| Roll | Probability | Effect |
|------|-------------|--------|
| Rarity | Varies by species | Determines rarity tier |
| Shiny | 1/64 (1.5625%) | Applies shiny modifier to profile |

The shiny roll fetches species data and persists the result into the profile frontmatter.

**资料来源：** [src/transport/ui/routes-write.ts:98-112]()

## Evolution System

The evolution system is implemented across multiple modules that track and process evolution-related claims:

### Evolution Claims

The `evolution-claims.ts` module handles the logic for processing evolution-related claims within the claims store. This system validates evolution conditions and updates profile states accordingly.

**资料来源：** [src/core/evolution-claims.ts](file context provided in repository)

### Evolution Workflow

```mermaid
graph LR
    A[Profile Created] --> B{Claims Accumulated}
    B -->|Sufficient| C[Evolution Trigger]
    B -->|Insufficient| D[Wait State]
    C --> E[Evolution Validation]
    E -->|Valid| F[Profile Updated]
    E -->|Invalid| G[Reject Evolution]
    F --> H[Platform Sync]
    D --> B
```

## Profile Identification

### Supported ID Patterns

The system supports multiple profile identification patterns:

| Pattern | Description | Example |
|---------|-------------|---------|
| Standard | `profile-<slug>.md` | `profile-fire-type.md` |
| Agent-specific | `profile-<agent-name>` | `profile-claude` |

**资料来源：** [src/core/pages.ts:45-60]()

### Path Resolution

The `pathForPage` function resolves profile paths:

```typescript
// Profile pages use the profiles subdirectory
const path = join(vaultPath, "wikis", wiki, "profiles", `${id}.md`);
```

**资料来源：** [src/core/pages.ts:47-49]()

## Stadium Platform Integration

### Client Architecture

The `StadiumClient` handles all communication with the Stadium platform:

- **Base URL**: Configured via `resolveStadiumConfig()`
- **Endpoint**: `/profiles/register` for profile creation
- **Error Handling**: Propagates `StadiumApiError` with `error_code`

**资料来源：** [src/tools/profile-register.ts:23]()

### Platform Data Flow

```
┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│   Vault File    │────▶│  profile-register │────▶│ Stadium API     │
│   (pokemon: X)  │     │  Tool            │     │ POST /register  │
└─────────────────┘     └──────────────────┘     └─────────────────┘
                              │                        │
                              ▼                        ▼
                        ┌──────────────────┐     ┌─────────────────┐
                        │ upsertPage()     │◀────│ profile_id      │
                        │ (persist result) │     │ stats           │
                        └──────────────────┘     └─────────────────┘
```

### Error Propagation

Server errors from the Stadium platform are propagated as `StadiumApiError`. Common error codes include:

- `pokeapi_unknown_species`: Species not found in platform
- Network failures: Caught and returned with descriptive messages

**资料来源：** [src/transport/ui/routes-write.ts:100-105]()

## Configuration and Defaults

| Setting | Default | Source |
|---------|---------|--------|
| Default Wiki | `_agents` | [routes-write.ts:78]() |
| Evolution Stage | `"basic"` | [routes-write.ts:90]() |
| Shiny Probability | 1/64 | [routes-write.ts:98-112]() |
| Platform Endpoint | `/profiles/register` | [profile-register.ts:23]() |

## Related Tools

| Tool | Purpose |
|------|---------|
| `vault.profile-register` | Register profile with Stadium platform |
| `vault.evolve-profile` | Trigger evolution on eligible profiles |
| `vault.refresh-profile-memory` | Update agent memory in profile |

**资料来源：** [src/tools/profile-register.ts:31-35]()

## Future Considerations

The current implementation (v1.5 convention) stores species information in the `pokemon` frontmatter field. The system maintains backward compatibility with the legacy `species_name` field for existing profiles. Future versions may expand the evolution system to include:

- Multi-stage evolution chains
- Evolution condition validation via claims
- Platform-synced evolution history

---

<a id='task-workflow'></a>

## Task Workflow System

### 相关页面

相关主题：[Channels and Claims](#channels-claims), [Core Concepts and Vocabulary](#concepts-vocabulary)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/core/tasks.ts](https://github.com/BrettNye/stoa/blob/main/src/core/tasks.ts)
- [src/tools/merge-record.ts](https://github.com/BrettNye/stoa/blob/main/src/tools/merge-record.ts)
- [src/core/frontmatter.ts](https://github.com/BrettNye/stoa/blob/main/src/core/frontmatter.ts)
- [src/core/eventbus/matchers/task.ts](https://github.com/BrettNye/stoa/blob/main/src/core/eventbus/matchers/task.ts)
- [src/core/disk-fallback.ts](https://github.com/BrettNye/stoa/blob/main/src/core/disk-fallback.ts)
- [README.md](https://github.com/BrettNye/stoa/blob/main/README.md)
</details>

# Task Workflow System

The Task Workflow System in Stoa provides a structured mechanism for creating, tracking, claiming, and resolving tasks across the vault's wiki-based knowledge management environment. It integrates with the broader event bus system for real-time state change notifications and supports atomic task claiming to prevent race conditions in multi-agent scenarios.

## Overview

The Task Workflow System serves as the coordination backbone for agent-driven work items within Stoa. It enables:

- **Task lifecycle management** — creation, status tracking, and resolution
- **Atomic claiming** — race-safe task assignment to agents
- **Two-phase task lookup** — fast index-based retrieval with disk-scan fallback
- **Event-driven state propagation** — real-time task status change notifications via the event bus
- **Optimistic Concurrency Control (OCC)** — safe concurrent updates using `expected_updated` timestamps

资料来源：[README.md:1-20]()

## Core Data Model

### Task Interface

```typescript
interface Task {
  id: string;
  title: string;
  type: string;
  wiki: string;
  status: string;
  claimed_by?: string;
  claimed_at?: string;
  updated: string;
  body: string;
}
```

The `Task` interface represents a work item stored as markdown frontmatter within `wikis/<wiki>/tasks/` directories. Key fields include:

| Field | Type | Description |
|-------|------|-------------|
| `id` | `string` | Unique task identifier (kebab-case per `HARD_KNOWLEDGE_TYPES`) |
| `wiki` | `string` | The wiki namespace containing this task |
| `status` | `string` | Current task status (e.g., `pending`, `claimed`, `merged`) |
| `claimed_by` | `string?` | Agent ID that claimed this task |
| `claimed_at` | `string?` | ISO timestamp when the task was claimed |
| `updated` | `string` | ISO date of last modification (used for OCC) |

资料来源：[src/core/tasks.ts:1-30]()

### Task Status Values

The system uses a defined set of task statuses aligned with the `PageStatus` enum:

| Status | Description |
|--------|-------------|
| `draft` | Initial state; task created but not ready for work |
| `active` | Task is open and in progress |
| `claimed` | Task has been assigned to an agent |
| `merged` | Task work has been merged/completed |
| `archived` | Task is no longer active |

资料来源：[src/core/frontmatter.ts:1-20]()

## Task Lookup Architecture

Stox implements a two-phase task lookup strategy to balance performance with data freshness.

```mermaid
graph TD
    A[Find Task by ID] --> B{Fast Path:<br/>Index Lookup}
    B -->|Found| C[Return Task]
    B -->|Not Found| D{Slow Path:<br/>Disk Scan}
    D -->|Found| C
    D -->|Not Found| E[Return null]
```

### Phase 1: Fast Path — Index Lookup

The system first queries `_index/pages.json` for the task:

```typescript
const idx = loadIndex(vaultPath);
const hit = idx.pages.find(p => p.id === taskId && p.type === "task");
if (hit) {
  return {
    wiki: hit.wiki,
    updated: hit.updated,
    status: String((hit as any).status ?? "")
  };
}
```

This path executes in O(n) on the index array and succeeds for all tasks that have been indexed since their last modification. 资料来源：[src/tools/merge-record.ts:1-40]()

### Phase 2: Slow Path — Disk Scan Fallback

When the index lacks the task (e.g., tasks authored directly on disk between reindexes), the system falls back to a disk scan:

```typescript
return findTaskOnDisk(vaultPath, taskId);
```

The `findTaskOnDisk` function delegates to the generalized `findOnDisk` utility in `core/disk-fallback.ts`, restricting results to `type: "task"`. This handles the case surfaced in Phase-3 Wave 5 T5-3 where tasks created via direct file authoring were immediately followed by a `vault.merge-record` call that silently missed the transition. 资料来源：[src/core/tasks.ts:1-30]()

## Task Claiming

The atomic task claiming mechanism prevents race conditions when multiple agents attempt to claim the same task simultaneously.

### Claim Operation

```typescript
export class AlreadyClaimedError extends Error {
  code = "AlreadyClaimed" as const;
}
```

When an agent attempts to claim a task:

1. The system loads the current task state
2. If `claimed_by` is already set, the race-loser receives `AlreadyClaimedError`
3. If unclaimed, the task is atomically updated with `claimed_by` and `claimed_at`

The `vault.task-claim` tool implements this atomicity, ensuring only one agent successfully claims a task. 资料来源：[src/tools/task-claim.ts]()

### Task Transition Rules

The `merge-record.ts` module defines conditional task transition logic:

```typescript
function computeTaskTransition(status: string, task_id: string): TaskTransition | null {
  // Returns a transition only when status === "merged" AND task_id is non-empty
  // For all halt/fail statuses it returns null and the task is NOT touched
}
```

This rule ensures that:
- Only `merged` status triggers a task transition
- The journal is written regardless of whether the task update succeeds
- Failure/halt journals are safe to re-run without side effects

资料来源：[src/tools/merge-record.ts:1-60]()

## Event Bus Integration

The task system integrates with Stoa's event bus for real-time state change notifications.

### Task State Matcher

```typescript
export const taskStateMatcher: VaultStateMatcher = {
  key: "task",
  extractKey(parsed) { return String(parsed.frontmatter.id); },
  diff(prev, cur) {
    if (cur.status === prev.status && cur.owner === prev.owner) {
      return { emit: false };
    }
    const enrichment: Partial<VaultEvent> = {};
    if (cur.status !== prev.status) {
      enrichment.task_status_change = { from: prev.status, to: cur.status };
    }
    if (cur.owner !== prev.owner) {
      enrichment.task_owner_change = { from: prev.owner, to: cur.owner };
    }
    return { emit: true, enrichment };
  },
  nextState(parsed) { return pickTaskState(parsed.frontmatter); },
  init(_path, parsed) { return pickTaskState(parsed.frontmatter); },
};
```

The matcher extracts task state from frontmatter and emits events for:
- `task_status_change` — when status transitions (e.g., `active` → `merged`)
- `task_owner_change` — when `claimed_by` changes

资料来源：[src/core/eventbus/matchers/task.ts:1-30]()

### State Extraction

```typescript
function pickTaskState(fm: Record<string, any>): TaskState {
  return {
    status: String(fm.status ?? "draft"),
    owner: fm.claimed_by ? String(fm.claimed_by) : undefined,
  };
}
```

## Task Operations

### Available Task Tools

| Tool | Description |
|------|-------------|
| `vault.task-create` | Create a new task in a specified wiki |
| `vault.task-list` | List tasks with optional filters |
| `vault.task-update` | Update task fields (status, claimed_by, etc.) |
| `vault.task-claim` | Atomically claim a pending task |

资料来源：[README.md:1-20]()

### Optimistic Concurrency Control

Task updates use OCC to prevent lost updates:

```typescript
interface ReleaseInput {
  task_id: string;
  expected_updated: string;  // Timestamp from last known state
  wiki: string;
  reason?: string;
}
```

The system compares the provided `expected_updated` against the current `updated` value. If they match, the update proceeds; otherwise, it fails to prevent concurrent modification.

## Journal Integration

When `merge-record.ts` processes a merged pull request:

1. Writes journal file at `wikis/_agents/journal/<journal_id>.md`
2. Idempotent rewrite — same `now` + same input produces same `journal_id`
3. Conditional task transition via `computeTaskTransition`
4. `task_updated: false` when task_id not found, but journal still written

资料来源：[src/tools/merge-record.ts:1-30]()

## Configuration

Task behavior is configurable via `_meta/lint-config.yaml`:

| Key | Default | Description |
|-----|---------|-------------|
| `task.min_cluster_size` | `3` | Minimum cluster size for synthesis debt detection |

Note: Task-specific configuration loading is pending (resolution-lifecycle spec implementation).

## Related Concepts

- **Synthesis Debt** — Tasks may be created to address synthesis clusters
- **Claim Clustering** — Related claim grouping logic
- **Task Readiness** — Determines when tasks are ready for claiming
- **Event Bus** — Real-time task event propagation

---

<a id='channels-claims'></a>

## Channels and Claims

### 相关页面

相关主题：[Task Workflow System](#task-workflow), [Event Bus System](#event-bus-system)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/core/channel.ts](https://github.com/BrettNye/stoa/blob/main/src/core/channel.ts)
- [src/core/decay.ts](https://github.com/BrettNye/stoa/blob/main/src/core/decay.ts)
- [src/core/claim-render.ts](https://github.com/BrettNye/stoa/blob/main/src/core/claim-render.ts)
- [src/tools/claim.ts](https://github.com/BrettNye/stoa/blob/main/src/tools/claim.ts)
- [src/core/synthesize.ts](https://github.com/BrettNye/stoa/blob/main/src/core/synthesize.ts)
- [src/core/frontmatter.ts](https://github.com/BrettNye/stoa/blob/main/src/core/frontmatter.ts)
- [src/core/lint.ts](https://github.com/BrettNye/stoa/blob/main/src/core/lint.ts)
</details>

# Channels and Claims

## Overview

Channels and Claims are two interconnected systems within the Stoa vault that enable coordination and knowledge assertion respectively. Channels provide a pub/sub mechanism for cross-instance communication, while Claims represent structured knowledge assertions with built-in confidence scoring and temporal decay.

## Channels

### Purpose

Channels enable coordination and communication across multiple vault instances or agents. They function as a lightweight messaging layer backed by journal pages stored directly in the vault filesystem.

### Architecture

Channels are implemented as journal pages with a `channel` field in their frontmatter. The system leverages the existing page indexing infrastructure rather than maintaining a separate message broker.

```mermaid
graph TD
    A[Agent/Instance] -->|vault.channel-post| B[Journal Page]
    B -->|type: journal<br/>channel: &lt;name&gt;<br/>wiki: &lt;wiki&gt;| C[Vault FS]
    D[Other Agent] -->|vault.channel-tail| E[Channel Summary]
    C -->|queryPages idx| E
```

### Channel Naming Convention

Channels must follow a strict naming format validated at lint time:

| Format | Regex | Example |
|--------|-------|---------|
| Lowercase kebab-case | `^[a-z0-9]+(-[a-z0-9]+)*$` | `pr-reviews`, `task-alerts` |

Validation is enforced in `src/core/lint.ts`:

```typescript
if (p.channel && !/^[a-z0-9]+(-[a-z0-9]+)*$/.test(p.channel)) {
  diagnostics.push({
    severity: "warning", code: "BAD_CHANNEL_FORMAT",
    page_id: p.id, wiki: p.wiki,
    message: `channel "${p.channel}" must be lowercase kebab-case`
  });
}
```
资料来源：[src/core/lint.ts:47-54]()

### Channel Summaries

The `channel-tail` tool aggregates journal entries into summaries containing:

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Channel identifier |
| `wiki` | string | Wiki where the channel exists |
| `lastEntry` | object | Most recent entry with id, author, ts, excerpt |
| `count24h` | number | Entries within the last 24 hours |

Each summary caches author information and body excerpts (first 240 characters) from the actual page files to avoid repeated filesystem reads during aggregation.

资料来源：[src/core/channel.ts:21-35]()

### Resolving Channel Scope

Channel queries are scoped by wiki. When listing or tailing channels, the system filters pages by:

1. `type === "journal"` — Only journal pages participate in channels
2. `wiki === opts.wiki` — Wiki isolation is enforced

```typescript
const pages = queryPages(idx, { type: "journal", wiki: opts.wiki });
```
资料来源：[src/core/channel.ts:18]()

## Claims

### Purpose

Claims represent structured knowledge assertions within the vault. They carry explicit confidence levels that decay over time, creating a system where knowledge freshness is tracked and surfaced.

### Data Model

Claims are stored as pages with the following frontmatter structure:

```yaml
id: <slug>
type: claim
title: <human-readable title>
authored_by: <agent-or-human>
confidence: high | medium | low
status: pending | accepted | retracted | rejected
evidence:
  - [[wikis/<wiki>/<type>/<id>]]
last_validated: YYYY-MM-DD
created: YYYY-MM-DD
updated: YYYY-MM-DD
```

### Confidence Decay

Claims use a temporal decay model to represent knowledge staleness. The effective confidence decreases based on:

1. **Initial confidence level** — `high`, `medium`, or `low`
2. **Time since last validation** — Measured in days
3. **Configured half-life** — Number of days for confidence to halve

The effective confidence formula is documented in `claim-render.ts`:

```typescript
const eff = effectiveConfidence(
  {
    confidence: claim.confidence,
    last_validated: claim.last_validated,
    status: claim.status,
  },
  today,
  {
    half_life_days: config.half_life_days,
    effective_floor: config.effective_floor,
  }
);
```
资料来源：[src/core/claim-render.ts:45-57]()

### Effective Confidence Computation

The decay system applies a floor to prevent confidence from reaching zero:

| Parameter | Default | Purpose |
|-----------|---------|---------|
| `half_life_days` | Configurable | Days for confidence to halve |
| `effective_floor` | Configurable | Minimum confidence value |

### Rendering Claims

Claims are rendered as bullet points in synthesis pages:

```markdown
- **`<key>`** — <body>. *(confidence <eff> as of <render-date>, validated <last_validated>, evidence: [[<first>]])*
```

The system:
- Rounds effective confidence to 2 decimal places
- Uses `claim.summary` if available, falling back to `claim.body`
- Includes only the first evidence entry
- Collapses internal whitespace to maintain single-line bullets

```typescript
// Collapse all internal whitespace runs (incl. embedded newlines) to a
// single space. `.trim()` alone leaves embedded `\n` intact, which would
// break the single-line bullet and corrupt the vault-claims:start..end
```
资料来源：[src/core/claim-render.ts:64-70]()

### Claim Lifecycle

```mermaid
stateDiagram-v2
  [*] --> pending: Creation
  pending --> accepted: Validation by curator
  pending --> rejected: Conflicting higher-confidence claim
  accepted --> retracted: Author retracts
  accepted --> rejected: Override with strictly higher confidence
  retracted --> [*]
  rejected --> [*]
```

### Claim Operations

#### Retraction

Authors may retract their own claims, recording:
- `retracted_at`: Timestamp of retraction
- `retracted_by`: Author performing retraction
- `retraction_reason`: Human-readable explanation

Only the original author may retract a claim:

```typescript
if (target.authored_by !== as) {
  throw new Error(
    `only the original author may retract claim ${claimId}: authored_by=${target.authored_by ?? "<unset>"}, as=${as}`,
  );
}
```
资料来源：[src/tools/claim.ts:85-90]()

#### Rejection

Claims are rejected when a higher-confidence claim on the same assertion already exists:

```typescript
return {
  claim_id: ex.id,
  action: "rejected",
  rejection: {
    reason: `existing claim ${ex.id} has effective confidence ${existingEffective.toFixed(3)}; submission's ${yourConfidence} is not strictly higher`,
    existing_id: ex.id,
    existing_effective_confidence: existingEffective,
    your_confidence: yourConfidence,
  },
};
```
资料来源：[src/tools/claim.ts:99-108]()

### Claim Sorting in Syntheses

When rendering synthesis pages, claims are sorted by a scoring function that accounts for effective confidence and profile affinity:

```typescript
const score = (c: ParsedClaim) => {
  const eff = effectiveConfidence(/* ... */);
  const boost = (c.profile ?? []).includes(deployingProfileId) ? 0.1 : 0;
  return eff + boost;
};
return [...claims].sort((a, b) => score(b) - score(a));
```
资料来源：[src/core/claim-render.ts:26-34]()

### Synthesis Integration

Claims are incorporated into synthesis pages via the `sources` frontmatter field:

```typescript
sources: inputIds.map(i => `[[wikis/${wiki}/${typeFolderForId(i)}/${i}]]`)
```
资料来源：[src/core/synthesize.ts:62]()

The synthesis metadata includes:

| Field | Value |
|-------|-------|
| `type` | `synthesis` |
| `status` | `draft` |
| `last_compiled` | ISO date of generation |

## Lint Rules

### Claim Scope Validation

Claims without scope (profile, move, scope_wiki, or tags) receive a warning:

```typescript
if (!allEmpty) return [];
return [{
  ruleId: "claim-with-no-scope",
  severity: "warn",
  line: 1,
  message: "Claim has no scope (profile/move/scope_wiki/tags all empty); no read path will surface it.",
}];
```
资料来源：[src/core/lint-checks/claim-with-no-scope.ts:17-24]()

### Channel Format Validation

Channel identifiers are validated during lint runs to ensure consistency:

| Check | Severity | Message |
|-------|----------|---------|
| Invalid kebab-case format | `warning` | `channel "<name>" must be lowercase kebab-case` |

## Related Tools

| Tool | Purpose |
|------|---------|
| `vault.channel-post` | Post a message to a coordination channel |
| `vault.channel-tail` | Pull recent entries from a channel |
| `vault.claim` | Submit, validate, or retract claims |
| `vault.synthesize` | Compile synthesis pages incorporating claims |

---

<a id='runtime-adapters'></a>

## Runtime Adapters

### 相关页面

相关主题：[Sync Agents and Skills](#sync-agents-skills), [Agent Profiles and Evolution](#profiles-evolution)

The repository context provided does not contain the source files required for this topic:

- `src/core/runtime-adapters/types.ts`
- `src/core/runtime-adapters/registry.ts`
- `src/core/runtime-adapters/claude-code.ts`
- `src/core/subagent-protocol.ts`
- `src/core/subagent-intent.ts`

These files are listed in the `<details>` block requirements but are **not present** in the retrieved repository context. Without access to these source files, I cannot generate an accurate technical wiki page about the Runtime Adapters feature.

**Available alternatives in the context:**

The context does contain `src/core/deployments.ts` which has partial runtime-related code:

```typescript
export interface DeploymentEntry {
  repo_path: string;
  target: "claude-code" | "openclaw" | "codex";
  mode: DeployMode;
  actual_mode?: DeployMode;
  synced_at: string;
  runtime?: RuntimeName;
  source_revision?: string;
  subagent_def_path?: string;
}
```

This shows runtime targets exist (`claude-code`, `openclaw`, `codex`) and a `RuntimeName` type is referenced, but the core runtime-adapters module files are needed to document the complete system.

**To proceed, please provide the content of the following files:**

1. `src/core/runtime-adapters/types.ts`
2. `src/core/runtime-adapters/registry.ts`
3. `src/core/runtime-adapters/claude-code.ts`
4. `src/core/subagent-protocol.ts`
5. `src/core/subagent-intent.ts`

Once these files are provided, I can generate the comprehensive technical wiki page with proper citations, Mermaid diagrams, and tables as requested.

---

<a id='sync-agents-skills'></a>

## Sync Agents and Skills

### 相关页面

相关主题：[Runtime Adapters](#runtime-adapters), [Agent Profiles and Evolution](#profiles-evolution)

<details>
<summary>Relevant Source Files</summary>

以下源码文件用于生成本页说明：

- [src/tools/sync-skills.ts](https://github.com/BrettNye/stoa/blob/main/src/tools/sync-skills.ts)
- [src/core/skills.ts](https://github.com/BrettNye/stoa/blob/main/src/core/skills.ts)
- [src/core/skills-platform.ts](https://github.com/BrettNye/stoa/blob/main/src/core/skills-platform.ts)
- [src/core/deployments.ts](https://github.com/BrettNye/stoa/blob/main/src/core/deployments.ts)
- [src/tools/claim.ts](https://github.com/BrettNye/stoa/blob/main/src/tools/claim.ts)
</details>

# Sync Agents and Skills

The sync agents and skills system is a core deployment mechanism that bridges the vault's canonical knowledge store with agent runtime environments. It provides two synchronized capabilities: **agent profile deployment** and **skills (moveset) deployment**, enabling consistent agent behavior across different execution contexts.

## Architecture Overview

The system operates across three layers:

| Layer | Purpose | Key Files |
|-------|---------|-----------|
| **CLI/API** | User-facing entry points | `src/tools/sync-skills.ts`, `src/cli/commands/sync-agents.ts` |
| **Core Logic** | Business rules and deployment orchestration | `src/core/skills.ts`, `src/core/skills-platform.ts` |
| **Persistence** | Deployment registry management | `src/core/deployments.ts` |

```mermaid
graph TD
    A["vault.sync-skills<br/>(MCP Tool)"] --> B["Read Profile<br/>wikis/&lt;wiki&gt;/profiles/&lt;profileId&gt;.md"]
    B --> C["Extract moves[]<br/>from profile frontmatter"]
    C --> D{"For each move"}
    D -->|Canonical path| E["wikis/_agents/moves/&lt;moveId&gt;/SKILL.md"]
    D -->|Deployed path| F["&lt;deployment.skills_dir&gt;/&lt;moveId&gt;/SKILL.md"]
    E --> G["probeSymlinkSupport()"]
    G --> H{"Host supports symlinks?"}
    H -->|Yes| I["fs.symlinkSync()"]
    H -->|No| J["recursiveCopy()"]
    I --> K["mode: 'symlink'"]
    J --> L["mode: 'copy'"]
    K --> M["Update _index/deployments.json"]
    L --> M
    M --> N["Return DeploymentEntry[]"]
```

资料来源：[src/tools/sync-skills.ts](https://github.com/BrettNye/stoa/blob/main/src/tools/sync-skills.ts)

## Core Concepts

### Deployment Target

The system supports multiple agent runtimes:

```typescript
type DeployTarget = "claude-code" | "openclaw" | "codex";
```

Each target represents a distinct agent runtime that consumes skills from the local filesystem. 资料来源：[src/core/deployments.ts:14](https://github.com/BrettNye/stoa/blob/main/src/core/deployments.ts#L14)

### Deploy Mode

Two deployment modes control how skills are materialized:

| Mode | Behavior | Fallback |
|------|----------|----------|
| `symlink` | Creates symbolic links from deployment directory to canonical vault files | Auto-falls back to `copy` on EPERM/EACCES/EEXIST |
| `copy` | Recursively copies the move directory to the deployment path | None |

The system automatically probes symlink support at `<targetDir>/.symlink-probe-<random>` before attempting symlink deployment. 资料来源：[src/core/skills-platform.ts:63-75](https://github.com/BrettNye/stoa/blob/main/src/core/skills-platform.ts#L63-L75)

### Drift Detection

The `detectDriftAt()` function compares canonical and deployed skill files using content hashing:

```typescript
export function detectDriftAt(
  deployment: DriftDeployment,
  vaultPath: string
): DriftReport[]
```

**Drift report rules:**

| Condition | Report | Action |
|-----------|--------|--------|
| Canonical missing | Throws | Vault integrity bug |
| Deployed missing | `{ kind: "missing", actual_hash: undefined }` | Deploy needed |
| Hashes differ | `{ kind: "hash-mismatch", actual_hash }` | Re-deploy needed |
| Hashes match | No entry (omit) | No action |

资料来源：[src/core/skills-platform.ts:27-40](https://github.com/BrettNye/stoa/blob/main/src/core/skills-platform.ts#L27-L40)

## Data Models

### DeploymentEntry

```typescript
export interface DeploymentEntry {
  repo_path: string;
  target: "claude-code" | "openclaw" | "codex";
  mode: DeployMode;
  actual_mode?: DeployMode;
  synced_at: string;

  // v1.7 additions
  runtime?: RuntimeName;
  source_revision?: string;
  subagent_def_path?: string;
}
```

The `actual_mode` field records whether symlinking was actually used (vs requested), enabling truthful reporting. 资料来源：[src/core/deployments.ts:19-31](https://github.com/BrettNye/stoa/blob/main/src/core/deployments.ts#L19-L31)

### DeploymentRegistry

```typescript
export type DeploymentRegistry = Record<string, DeploymentEntry[]>;
```

The registry is keyed by `profileId`, with each entry representing one deployment of that profile. Stored at `_index/deployments.json` at the vault root. 资料来源：[src/core/deployments.ts:33-34](https://github.com/BrettNye/stoa/blob/main/src/core/deployments.ts#L33-L34)

## Skills Structure

### Move Directory Layout

Skills (called "moves") follow a directory convention:

```
wikis/_agents/moves/
├── move-flamethrower/
│   └── SKILL.md
├── move-thunderbolt/
│   └── SKILL.md
└── move-protect/
    └── SKILL.md
```

- Each move is a directory containing a single `SKILL.md` file
- Move IDs are used as directory names
- The directory layout enables recursive deployment operations 资料来源：[src/core/skills-platform.ts:18-23](https://github.com/BrettNye/stoa/blob/main/src/core/skills-platform.ts#L18-L23)

### Profile Structure

Profiles reference moves via the `moves` frontmatter field:

```yaml
---
id: profile-charizard
title: Charizard Combat Profile
type: profile
wiki: _agents
moves:
  - move-flamethrower
  - move-thunderbolt
  - move-dragon-dance
---
```

The `moves` array is read during sync to determine which skills to deploy. 资料来源：[src/core/skills.ts](https://github.com/BrettNye/stoa/blob/main/src/core/skills.ts)

## Sync Workflow

### vault.sync-skills Tool

```mermaid
sequenceDiagram
    participant Client
    participant VaultMCP
    participant ProfileStore
    participant DeployModule
    participant Registry

    Client->>VaultMCP: vault.sync-skills({profile_id, wiki?})
    VaultMCP->>ProfileStore: Read wikis/<wiki>/profiles/<profile_id>.md
    ProfileStore-->>VaultMCP: Profile with moves[]
    
    VaultMCP->>VaultMCP: For each moveId in moves[]:
    VaultMCP->>DeployModule: probeSymlinkSupport(targetDir)
    DeployModule-->>VaultMCP: supportsSymlinks: boolean
    
    alt supportsSymlinks
        VaultMCP->>DeployModule: deployMove(src, dest, "symlink")
    else
        VaultMCP->>DeployModule: deployMove(src, dest, "copy")
    end
    
    DeployModule->>Registry: Update _index/deployments.json
    VaultMCP-->>Client: DeploymentEntry[]
```

### Deployment Persistence

The registry stores each deployment with idempotent semantics:

```typescript
export function writeDeployments(vaultPath: string, registry: DeploymentRegistry): void
export function readDeployments(vaultPath: string): DeploymentRegistry
```

Re-running sync with identical inputs produces byte-identical registry output. 资料来源：[src/core/deployments.ts:38-52](https://github.com/BrettNye/stoa/blob/main/src/core/deployments.ts#L38-L52)

## Configuration

### Vault Path Resolution

| Priority | Source | Key |
|----------|--------|-----|
| 1 | `--vault=` CLI flag | `config.vaultPath` |
| 2 | `STOA_VAULT_PATH` env var | Falls through to default |
| 3 | Working directory | `.` |

### Wiki Resolution

| Priority | Source |
|----------|--------|
| 1 | `wiki:` argument on tool call |
| 2 | `--default-wiki=<name>` CLI flag |
| 3 | `.active-wiki` file at vault root |

### Target Directory

Deployment target directories are specified in the deployment registry entry. The `repo_path` determines where skills are deployed relative to the vault root or an absolute path.

## Error Handling

### Error Scenarios

| Scenario | Behavior | Recovery |
|----------|----------|----------|
| Unknown profile ID | `UnknownProfileError` | Provide valid profile ID |
| Missing canonical move | Throws during drift check | Vault integrity issue |
| Symlink permission denied | Auto-fallback to `copy` | Transparent |
| Deployment file locked | Propagates error | Retry |
| Profile missing `moves` field | Empty deployment | Check profile definition |

### Claim Retraction Integration

The deployment system integrates with the claims subsystem for agent identity verification:

```typescript
if (target.authored_by !== as) {
  throw new Error(
    `only the original author may retract claim ${claimId}`
  );
}
```

This ensures deployment operations respect agent authorship boundaries. 资料来源：[src/tools/claim.ts:42-46](https://github.com/BrettNye/stoa/blob/main/src/tools/claim.ts#L42-L46)

## CLI Integration

### Commands

```bash
stoa --vault=/path/to/vault sync-skills --profile=profile-charizard --wiki=_agents
```

### Idempotency

- Same profile + same inputs = same output (byte-identical)
- `source_revision` enables short-circuit of re-deploys
- Drift detection prevents unnecessary re-synchronization

## Backward Compatibility

The deployment system maintains backward compatibility across versions:

| Version | Change | Compatibility |
|---------|--------|----------------|
| v1.5 | Original schema | Base |
| v1.6 | Added `actual_mode` | Defaults `actual_mode` to `mode` |
| v1.7 | Added `runtime`, `source_revision`, `subagent_def_path` | Defaults `runtime` to `target` |

```typescript
// Back-compat: v1.5 entries lack actual_mode. Default to mode.
const actualMode = entry.actual_mode ?? entry.mode;

---

<a id='tool-categories'></a>

## Tool Categories Reference

### 相关页面

相关主题：[Introduction to Stoa](#introduction), [Channels and Claims](#channels-claims)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/core/synthesize.ts](https://github.com/BrettNye/stoa/blob/main/src/core/synthesize.ts)
- [src/core/syntheses.ts](https://github.com/BrettNye/stoa/blob/main/src/core/syntheses.ts)
- [src/core/lint-checks/synthesis-debt.ts](https://github.com/BrettNye/stoa/blob/main/src/core/lint-checks/synthesis-debt.ts)
- [src/core/channel.ts](https://github.com/BrettNye/stoa/blob/main/src/core/channel.ts)
- [src/core/frontmatter.ts](https://github.com/BrettNye/stoa/blob/main/src/core/frontmatter.ts)
- [src/transport/stdio.ts](https://github.com/BrettNye/stoa/blob/main/src/transport/stdio.ts)
- [README.md](https://github.com/BrettNye/stoa/blob/main/README.md)
</details>

# Tool Categories Reference

## Overview

The Stoa vault system exposes a collection of MCP (Model Context Protocol) tools organized into logical categories that handle knowledge retrieval, content creation, channel coordination, and linting operations. These tools operate on a vault directory structure where wikis contain typed pages with structured frontmatter and markdown bodies.

The tool system is designed around a wiki-centric data model where pages are typed (concept, spec, decision, synthesis, etc.), tagged, and optionally scoped to wikis or families. Tools provide both pull-based operations (read, recall) and push-based primitives (wait-for, channel-post), enabling both synchronous queries and event-driven workflows.

资料来源：[README.md:1-50]()

## Tool Category Taxonomy

The available tools are organized into four primary categories:

| Category | Purpose | Typical Consumer |
|----------|---------|------------------|
| **Read — pull primitives** | Query existing vault content | Agents, humans |
| **Write — content** | Create or modify vault pages | Agents |
| **Wait — push primitives** | Block until vault events occur | Event-driven workflows |
| **Coordination** | Cross-instance communication and task management | Multi-agent systems |

资料来源：[README.md:1-50]()

## Read Primitives

Read tools retrieve information from the vault index or direct file access without modifying state.

### Recall

The `vault.recall` tool searches the vault index for pages matching query parameters. It supports filtering by wiki, type, status, channel, and layer (knowledge vs execution types). Results include relevance-ranked hits with IDs and metadata.

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `topic` | string | Search query text |
| `wiki` | string (optional) | Limit to specific wiki |
| `layer` | `"all" \| "knowledge" \| "execution"` | Filter by page type category |
| `type` | string (optional) | Filter by exact page type |
| `status` | string (optional) | Filter by page status |
| `channel` | string (optional) | Filter by channel name |
| `limit` | number | Maximum results (default 25) |

The recall mechanism uses tokenized full-text search with stop-word removal and stemming via the Porter stemmer. Results are ranked by relevance.

资料来源：[src/core/index.ts:1-50]()

### Read

The `vault.read` tool fetches a specific page by ID or path, returning parsed frontmatter and body content. Unlike recall which searches, read is a direct lookup operation.

### Lint

The `vault.lint` tool runs diagnostic checks against the vault corpus. Lint checks validate structural properties and frontmatter invariants across the index.

**Available Lint Checks:**

| Code | Severity | Description |
|------|----------|-------------|
| `SYNTHESIS_DEBT` | warning | Hard-knowledge clusters without synthesis coverage |
| `CLAIM_WITH_NO_SCOPE` | warn | Claims missing all scope fields |
| `CROSS_WIKI_LINK_BROKEN` | error | Wikilinks pointing to non-existent pages |

The lint system distinguishes between Group A rules (fast, frontmatter-only) and Group B rules (claim-file parsing required). Synthesis debt is a structural-property rule that scales with vault growth since it requires no content reads.

资料来源：[src/core/lint-checks/synthesis-debt.ts:1-60]()
资料来源：[src/core/lint-checks/claim-with-no-scope.ts:1-30]()

## Write Primitives

Write tools create or modify vault content. These operations are idempotent where possible and preserve manual edits.

### Synthesize

The `vault.synthesize` tool compiles or refreshes a synthesis page from a set of input pages. Syntheses are mid-tier hub pages that distill clusters of related concepts, specs, or decisions into recallable views.

**Synthesis Modes:**

| Scope | ID Pattern | Wiki | Purpose |
|-------|------------|------|---------|
| `topic` | `synthesis-<slug>` | configurable (default: alpha) | General topic synthesis |
| `memory` | `synthesis-<agent>-memory` | `_agents` | Per-agent memory compilation |

**Frontmatter Template:**

```yaml
id: synthesis-<slug>
title: "<topic> — synthesis"
type: synthesis
wiki: alpha
status: draft
created: <today>
updated: <today>
summary: "Synthesis of <N> pages on <topic>"
tags: []
last_compiled: <today>
sources:
  - [[wikis/alpha/concept/page-id-1]]
  - [[wikis/alpha/spec/page-id-2]]
```

The synthesis tool preserves manual edits in protected zones bounded by `<!-- manual_notes:start ... -->` and `<!-- manual_notes:end -->` markers. Re-compiles extract and re-apply content from these zones without losing human-authored prose.

资料来源：[src/core/synthesize.ts:1-100]()
资料来源：[src/core/frontmatter.ts:1-80]()

### Inbox

The `vault.inbox` tool captures fleeting thoughts to the active wiki's `inbox/` directory. This provides a low-friction capture mechanism for ideas that don't yet warrant a full typed page.

### New

The `vault.new` tool creates a typed page from a template. Supported types include:

| Type | Filename Pattern | Notes |
|------|------------------|-------|
| `concept` | `concept-<slug>.md` | Knowledge atom |
| `spec` | `spec-<slug>.md` | Technical specification |
| `decision` | `decision-YYYY-MM-DD-<slug>.md` | Date-prefixed |
| `journal` | `journal-YYYY-MM-DD-HHMM-<slug>.md` | Date+time required |
| `move` | `move-<slug>/SKILL.md` | Directory layout |
| `map` | `map.md` | Fixed canonical filename |
| `synthesis` | `synthesis-<slug>.md` | Hub page |
| `claim` | `claim-<slug>.md` | Assertion with evidence |
| `idea` | `idea-<slug>.md` | Unvalidated concept |
| `question` | `question-<slug>.md` | Open inquiry |
| `source` | `source-<slug>.md` | External citation |
| `guide` | `guide-<slug>.md` | Procedural documentation |

资料来源：[src/core/ids.ts:1-50]()

### Agent Journal

The `vault.agent-journal` tool appends a first-person agent reflection at end-of-task. Journals are typed pages with `channel: agent-log` that capture agent decision rationale and state transitions.

## Wait (Push Primitives)

Wait tools implement blocking semantics for event-driven workflows, replacing polling with cursor-based catch-up.

| Tool | Semantics |
|------|-----------|
| `vault.wait-for` | Block until one matching event lands |
| `vault.wait-for-any` | Wake on first match across N filters (race) |
| `vault.wait-for-all` | Wake when all N filters have matched at least once |
| `vault.wait-for-many` | Bounded batch over a window |

These primitives use the stdio transport for MCP communication, maintaining a state cache for diffing prior and current vault events.

资料来源：[src/transport/stdio.ts:1-80]()
资料来源：[src/core/eventbus/state-cache.ts:1-40]()

## Coordination Tools

### Channel Post

The `vault.channel-post` tool posts to a coordination channel, enabling cross-instance communication. Channels are scoped to wikis and identified by kebab-case names.

**Channel Entry Structure:**

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Page ID |
| `channel` | string | Channel name |
| `wiki` | string | Wiki scope |
| `author` | string | Author identifier |
| `ts` | ISO date | Timestamp |
| `excerpt` | string | First 240 chars of body |
| `pageId` | string | Reference to full page |

The channel system aggregates journal entries and provides 24-hour activity counts for monitoring.

资料来源：[src/core/channel.ts:1-80]()

### Task Claim

The `vault.task-claim` tool atomically claims a pending task. Race losers receive an `AlreadyClaimedError`, ensuring exactly-once task assignment in multi-agent scenarios.

### Bootstrap Repo

The `vault.bootstrap-repo` tool wires a consuming repository with `.mcp.json` and a `CLAUDE.md` fragment, establishing the MCP configuration and agent instructions.

### Sync Skills

The `vault.sync-skills` tool deploys agent profiles to a target skills directory, maintaining drift detection between canonical vault sources and deployed skill files.

**Drift Detection:**

| Condition | Behavior |
|-----------|----------|
| Canonical missing | Throw (vault-integrity bug) |
| Deployed missing | Emit `{ kind: "missing", actual_hash: undefined }` |
| Hash mismatch | Emit `{ kind: "hash-mismatch", actual_hash }` |
| Hashes match | Omit from report |

资料来源：[src/core/skills-platform.ts:1-80]()

### Reindex

The `vault.reindex` tool regenerates `_index/` files and per-wiki `index.md`, rebuilding the search index after bulk operations or corruption recovery.

## Synthesis Staleness Tracking

The system tracks when synthesis pages were last compiled to identify debt. Staleness is computed as the difference between current time and `last_compiled` frontmatter field.

| Metric | Calculation |
|--------|-------------|
| `lag_days` | `(now - compiledMs) / MS_PER_DAY` |
| Filter | `min_lag_days` threshold (default: none) |

This enables curators to identify syntheses that haven't been refreshed despite upstream changes to their source pages.

资料来源：[src/core/syntheses.ts:1-80]()

## Tool Data Flow

```mermaid
graph TD
    subgraph "Read Primitives"
        R[Recall] -->|index query| I[VaultIndex]
        RD[Read] -->|direct file| F[Markdown files]
    end
    
    subgraph "Write Primitives"
        S[Synthesize] -->|read prior| F
        S -->|write| N[New file]
        IN[Inbox] -->|append| I
        AJ[Agent Journal] -->|append| C[Channel]
    end
    
    subgraph "Event System"
        W[Wait-for tools] -->|subscribe| E[Event Bus]
        E -->|state diff| SC[State Cache]
    end
    
    subgraph "Coordination"
        CP[Channel Post] -->|broadcast| C
        TC[Task Claim] -->|atomic| T[Task Registry]
    end
    
    subgraph "Validation"
        L[Lint] -->|check| CH[Claim Handlers]
        L -->|check| SD[Synthesis Debt]
        L -->|check| CW[Claim Scope]
    end
    
    I -.->|rebuild| R
    F -.->|parse| I
```

## Page Type Layering

The system distinguishes between two semantic layers:

| Layer | Types | Role |
|-------|-------|------|
| **Knowledge** | concept, spec, decision, synthesis | Durable thinking content |
| **Execution** | guide, source, idea, question | Procedural and citation |

Recall and synthesis debt checks filter by layer, enabling scope-aware queries that don't mix execution metadata into knowledge graph traversals.

资料来源：[src/core/index.ts:1-50]()
资料来源：[src/core/lint-checks/synthesis-debt.ts:1-60]()

## Family Resolution

Tools can operate at wiki or family scope. Family resolution follows a priority cascade:

```mermaid
graph LR
    A[CLI --family arg] --> B{Match?}
    B -->|yes| Z[Return family]
    B -->|no| C[Check .active-family file]
    C --> D{Exists?}
    D -->|yes| Z
    D -->|no| E[Use defaultFamily config]
    E --> F{Configured?}
    F -->|yes| Z
    F -->|no| G[Return null - single wiki]
```

When a wiki is explicitly specified alongside a family argument, the system validates consistency and throws `FamilyMismatchError` on mismatch.

资料来源：[src/core/family.ts:1-80]()

## Wikilink Resolution

Tools consume and produce wikilinks in the vault-root absolute form: `[[wikis/<wiki>/<type>/<id>(|alias)]]`. The wikilink extractor is code-fence-aware and handles both body content and frontmatter `related:` arrays.

| Behavior | Scope |
|----------|-------|
| Top-level fenced blocks | Stripped |
| Indented fenced blocks | Preserved |
| Inline code spans | Preserved |
| Malformed links | Silently skipped |

资料来源：[src/core/wikilinks.ts:1-50]()

## Configuration

Tools read configuration from `vault-mcp.json` in the vault root:

| Key | Description |
|-----|-------------|
| `vaultPath` | Absolute path to vault directory |
| `defaultWiki` | Fallback wiki when unspecified |
| `defaultFamily` | Fallback family scope |

The stdio server logs its configuration on startup: `vault-mcp stdio server ready (vault=<path>, default-wiki=<wiki>, default-family=<family>)`.

资料来源：[src/transport/stdio.ts:1-80]()

---

---

## Doramagic 踩坑日志

项目：BrettNye/stoa

摘要：发现 7 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：配置坑 - 可能修改宿主 AI 配置。

## 1. 配置坑 · 可能修改宿主 AI 配置

- 严重度：medium
- 证据强度：source_linked
- 发现：项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。
- 对用户的影响：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。
- 建议检查：列出会写入的配置文件、目录和卸载/回滚步骤。
- 防护动作：涉及宿主配置目录时必须给回滚路径，不能只给安装命令。
- 证据：capability.host_targets | github_repo:1229401738 | https://github.com/BrettNye/stoa | host_targets=mcp_host, claude, claude_code

## 2. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | github_repo:1229401738 | https://github.com/BrettNye/stoa | README/documentation is current enough for a first validation pass.

## 3. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | github_repo:1229401738 | https://github.com/BrettNye/stoa | last_activity_observed missing

## 4. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | github_repo:1229401738 | https://github.com/BrettNye/stoa | no_demo; severity=medium

## 5. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | github_repo:1229401738 | https://github.com/BrettNye/stoa | no_demo; severity=medium

## 6. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | github_repo:1229401738 | https://github.com/BrettNye/stoa | issue_or_pr_quality=unknown

## 7. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：evidence.maintainer_signals | github_repo:1229401738 | https://github.com/BrettNye/stoa | release_recency=unknown

<!-- canonical_name: BrettNye/stoa; human_manual_source: deepwiki_human_wiki -->
