Files
claude-archeflow-plugin/skills/colette-bridge/SKILL.md
Christian Nennemann af1f4e7da7 refactor: merge attention-filters into check-phase skill
Consolidate the attention-filters skill (122 lines) into check-phase,
reducing check-phase from 234 to 110 lines. Removed verbose bash code
blocks, 30-line consolidated output example, re-check protocol (belongs
in act-phase), and motivational section. Updated all references in
README, plugin.json, using-archeflow, and colette-bridge.
2026-04-06 20:41:36 +02:00

14 KiB

name, description
name description
colette-bridge Bridges ArcheFlow with the Colette writing platform. Auto-detects colette.yaml in the project root, resolves voice profiles, personas, and character sheets, then builds a summarized context bundle that gets injected into every agent prompt via artifact routing. Eliminates manual copy-pasting of writing context into agent prompts. <example>Automatically loaded when colette.yaml is detected at run.start</example> <example>User: "archeflow:run" in a project with colette.yaml</example>

Colette Bridge — Writing Context Auto-Loader

When ArcheFlow detects colette.yaml in the project root, this skill automatically loads voice profiles, personas, character sheets, and project rules into a context bundle that every agent receives (filtered by archetype role).

Prerequisites

  • archeflow:domains — Colette Bridge sets domain to writing automatically
  • archeflow:artifact-routing — bundle is injected via the artifact routing system
  • archeflow:run — bridge hooks into run initialization

Trigger

At run.start, after domain detection but before the Plan phase:

  1. Check if colette.yaml exists in the project root
  2. If found, activate Colette Bridge
  3. If not found, skip silently (no error, no warning)

When the bridge activates, it emits a decision event:

./lib/archeflow-event.sh "$RUN_ID" decision init "" \
  '{"what":"colette_bridge","chosen":"activated","signal":"colette.yaml found","files_resolved":<count>}'

File Resolution

Colette projects reference files by ID (e.g., vp-giesing-gschichten-v1) but the actual YAML files may live in different locations. The bridge resolves files using this search order:

Search Priority (highest first)

Priority Location Example
1 Explicit path in colette.yaml voice.profile: ../writing.colette/profiles/custom.yaml
2 Project root subdirectories ./profiles/vp-giesing-gschichten-v1.yaml
3 Parent directory + writing.colette/ ../writing.colette/profiles/vp-giesing-gschichten-v1.yaml

What Gets Resolved

Source colette.yaml field Search paths
Voice profile voice.profile profiles/<id>.yaml, ../writing.colette/profiles/<id>.yaml
Persona writing.persona or inferred from profile personas/<id>.yaml, ../writing.colette/personas/<id>.yaml
Characters Auto-discovered characters/*.yaml
Series config series section (if present) colette.yaml itself, ../writing.colette/series/<name>.yaml
Project rules Always CLAUDE.md in project root

Resolution Procedure

for each reference in colette.yaml:
  1. If the field contains a path (has / or .yaml) → use as-is, verify exists
  2. If the field contains an ID (e.g., "vp-giesing-gschichten-v1"):
     a. Check ./profiles/<id>.yaml (or ./personas/<id>.yaml)
     b. Check ../writing.colette/profiles/<id>.yaml (or ../writing.colette/personas/<id>.yaml)
     c. If not found → warn in event log, skip this file
  3. For characters/ → glob characters/*.yaml in project root
  4. For CLAUDE.md → check project root

If a referenced file cannot be found at any location, emit a warning event but do not abort:

./lib/archeflow-event.sh "$RUN_ID" decision init "" \
  '{"what":"colette_bridge_warning","chosen":"skip","file":"vp-giesing-gschichten-v1","reason":"not found in any search path"}'

Context Bundle

The bridge generates .archeflow/context/colette-bundle.md — a summarized, token-efficient Markdown file that agents receive as part of their prompt context.

Bundle Structure

# Writing Context (auto-loaded from Colette)

## Voice Profile: <id>
**Tone:** <tone_summary from meta>
**Perspective:** <perspektive>
**Density:** <dichte>
**Attitude:** <haltung>
**Sharpness:** <schaerfe>
**Humor:** <humor>
**Tempo:** <tempo>
**Reader relationship:** <leser_beziehung>

### Forbidden
- <each item from verboten>

### Allowed
- <each item from erlaubt>

### Style models
- <each item from vorbilder, name only + one-word tag>

## Persona: <id>
**Name:** <name>
**Bio:** <bio, max 2 sentences>
**Genres:** <genres, comma-separated>

### Rules
- <each item from rules>

## Characters
### <name> (<role>)
- **Age:** <age>
- **Key traits:** <first 3 personality items>
- **Speech:** <speech_pattern, first sentence only>
- **Relationships:** <key relationships, one line each>

[Repeated for each character in characters/*.yaml]

## Series Context
[Only if series config found in colette.yaml]
- **Shared concepts:** <list>
- **Glossary:** <key terms>
- **Forbidden cross-story:** <items>

## Project Rules (from CLAUDE.md)
[Key writing rules extracted from CLAUDE.md, summarized as bullet points]
- <rule 1>
- <rule 2>
- ...

Summarization Rules

The bundle is summarized, not a raw YAML dump. This reduces token cost:

  • Voice profile dimensions: key name + value (no YAML formatting, no dimensionen: wrapper)
  • Verboten/erlaubt: bullet list, strip explanation after the dash if over 15 words
  • Characters: name, role, age, top 3 traits, first sentence of speech pattern, relationships
  • Persona bio: max 2 sentences
  • CLAUDE.md: extract only rules/style sections, skip meta/git/cost config
  • Target: bundle should be under 1500 tokens for a typical project

Caching

The bundle is regenerated only when source files have changed. Cache validation uses file modification times.

Cache Check Procedure

bundle_path = .archeflow/context/colette-bundle.md

if bundle_path does not exist → generate
if bundle_path exists:
  bundle_mtime = mtime of bundle_path
  for each resolved source file:
    if source_mtime > bundle_mtime → regenerate, break
  if no source file is newer → use cached bundle

When the cache is valid, emit:

./lib/archeflow-event.sh "$RUN_ID" decision init "" \
  '{"what":"colette_bundle_cache","chosen":"reuse","reason":"all sources older than bundle"}'

When regenerating:

./lib/archeflow-event.sh "$RUN_ID" decision init "" \
  '{"what":"colette_bundle_cache","chosen":"regenerate","reason":"<file> modified since last bundle"}'

Per-Agent Attention Filters

Not every agent needs the full bundle. The bridge defines attention filters that control which sections each archetype receives. This extends the base attention filters from archeflow:check-phase.

Archetype Bundle sections injected Rationale
Explorer Full bundle Needs all context for research — setting, characters, voice, rules
Creator Voice dimensions + persona rules + characters Designs outline — needs to know who speaks how, who exists, what's allowed
Maker Full bundle Writes prose — needs voice for style, characters for dialogue, rules for guardrails
Guardian Characters + series shared_concepts Checks consistency — needs character facts and cross-story constraints
Sage Voice profile (full, including verboten/erlaubt) + persona rules Checks voice drift — needs the complete voice spec and persona constraints
Trickster Characters + series glossary Tests continuity — needs character facts and terminology for contradiction checks

Filter Implementation

When injecting the bundle into an agent prompt, extract only the relevant sections:

# For Guardian:
Extract: "## Characters" section (all characters)
Extract: "## Series Context" section (if present)
Skip: everything else

# For Sage:
Extract: "## Voice Profile" section (full, with forbidden/allowed)
Extract: "## Persona" section (rules subsection)
Skip: characters, series, project rules

# For Explorer and Maker:
Inject: full bundle as-is

The filtering happens at prompt assembly time, not at bundle generation time. One bundle, multiple filtered views.

Custom Archetypes

Custom archetypes (e.g., story-explorer, story-sage) inherit the filter of their closest base archetype:

Custom archetype Inherits filter from Override
story-explorer Explorer Full bundle
story-sage Sage Full voice profile + persona rules
story-guardian Guardian Characters + series

If a custom archetype needs a different filter, define it in the archetype's markdown frontmatter:

---
name: story-sage
colette_filter: [voice_profile, persona, characters]
---

The colette_filter field accepts section keys: voice_profile, persona, characters, series, project_rules, full.


Integration with Run Skill

The Colette Bridge hooks into archeflow:run initialization. The sequence is:

run.start
  ├── Domain detection (from archeflow:domains)
  │     └── colette.yaml found → domain = writing
  ├── Colette Bridge activation
  │     ├── Resolve files (voice profile, persona, characters, CLAUDE.md)
  │     ├── Check bundle cache
  │     ├── Generate/refresh bundle → .archeflow/context/colette-bundle.md
  │     └── Register bundle path in artifact routing
  └── Continue to Plan phase

Artifact Routing Registration

The bundle path is registered so that every phase's context injection includes the (filtered) bundle:

artifact_routing.register_context(
  path = ".archeflow/context/colette-bundle.md",
  inject_at = "all_phases",
  filter_by = "archetype"  # Apply per-agent attention filters
)

In practice, this means the run skill prepends the filtered bundle content to each agent's prompt, after the standard task description but before phase-specific artifacts.

Prompt Injection Order

1. Archetype definition (from SKILL.md or custom archetype .md)
2. Domain-specific review focus (from archeflow:domains)
3. Colette bundle (filtered for this archetype)
4. Task description
5. Phase-specific artifacts (Explorer output, Creator proposal, etc.)
6. Cycle feedback (if cycle 2+)

Example: Giesing Gschichten

Given this colette.yaml:

project:
  name: "Giesing Gschichten"
  author: "C. Nennemann"
  language: de
  type: fiction

voice:
  profile: vp-giesing-gschichten-v1

writing:
  target_words: 6000
  style: "Ich-Erzaehler, lakonisch, Eberhofer-meets-Grossstadt"

The bridge:

  1. Reads voice.profile: vp-giesing-gschichten-v1
  2. Searches for ./profiles/vp-giesing-gschichten-v1.yaml — not found
  3. Searches for ../writing.colette/profiles/vp-giesing-gschichten-v1.yaml — found
  4. Infers persona from voice profile ID pattern or searches personas/ — finds giesinger.yaml at ../writing.colette/personas/giesinger.yaml
  5. Globs characters/*.yaml — finds alex.yaml (and others if present)
  6. Reads CLAUDE.md for writing rules
  7. Generates bundle:
# Writing Context (auto-loaded from Colette)

## Voice Profile: vp-giesing-gschichten-v1
**Tone:** Lakonisch, warmherzig-genervt, trockener Humor
**Perspective:** Ich-Erzaehler (Alex), nah dran, subjektiv
**Density:** Alltagsdetails die Atmosphaere schaffen
**Attitude:** Lakonisch, leicht genervt, aber mit Herz
**Sharpness:** Beobachtungsscharf, sprachlich reduziert
**Humor:** Trocken, Understatement, absurde Situationen
**Tempo:** Gemaechlich mit Spannungsspitzen, Slow Burn
**Reader relationship:** Kumpel am Stammtisch

### Forbidden
- Hochdeutsch-Sterilitaet
- Krimi-Klischees (CSI, Profiler, Tatort)
- Lederhosen-Kitsch und Oktoberfest-Folklore
- Dialekt-Overkill
- Moralisieren oder Erklaeren
- Kuenstliche Spannungsaufbauten
- Adverb-Orgien und Adjektiv-Ketten
- Infodumps

### Allowed
- Bairische Einsprengsel in Hochdeutsch-Prosa
- Essen und Trinken als Leitmotiv
- Kiffer-Humor und Slow-Motion-Beobachtungen
- Gentrification-Satire
- Echte Giesinger Orte und Strassen
- Skurrile Nachbarn
- Kriminalplot aus dem Alltag
- Kurze, lakonische Dialoge

### Style models
- Rita Falk (Erzaehlton), Wolf Haas (lakonisch), Helmut Dietl (Muenchner Milieu), Friedrich Ani (duester), Bukowski (Anti-Held)

## Persona: giesinger
**Name:** Der Giesinger
**Bio:** Erzaehlt Geschichten aus Muenchen-Giesing. Eberhofer meets Grossstadt.
**Genres:** Krimi, Kurzgeschichte, Milieustudie

### Rules
- Ich-Erzaehler, immer — Alex erzaehlt
- Hauptsaechlich Hochdeutsch mit bairischen Einsprengsel
- Jede Geschichte hat einen Kriminalplot
- Essen/Trinken in jeder Geschichte
- Echte Giesinger Orte und Strassen
- Humor durch Understatement
- Alex ist kein Ermittler
- Figuren reden wie echte Menschen

## Characters
### Alex (protagonist)
- **Age:** Mitte 30
- **Key traits:** Lakonisch, funktionaler Kiffer, unmotiviert aber nicht dumm
- **Speech:** Kurze Saetze, Hochdeutsch mit bairischen Einsprengsel.
- **Relationships:** Mo — Nachbar, Kumpel und Unruhestifter

## Project Rules (from CLAUDE.md)
- Jede Geschichte beginnt mit einer Alltagsszene
- Kriminalplot ergibt sich organisch aus dem Alltag
- Essen/Trinken in jeder Geschichte
- Echte Giesinger Orte verwenden
- Kein Moralisieren, kein Erklaerbaer
- Ende muss nicht alles aufloesen

Design Principles

  1. Summarize, don't dump. Raw YAML wastes tokens and confuses agents. The bundle is a curated briefing.
  2. Cache aggressively. Voice profiles and characters rarely change mid-run. Only regenerate when mtimes change.
  3. Filter per agent. A Guardian checking plot consistency does not need the full voice profile. A Sage checking voice drift does not need character sheets.
  4. Graceful degradation. Missing files are warned about, not fatal. A project with colette.yaml but no characters/ still works — the Characters section is simply empty.
  5. One bundle, filtered views. Generate the full bundle once. Filter at injection time per archetype. This keeps caching simple.
  6. Additive to existing skills. The bridge does not replace domain detection or artifact routing — it hooks into them. Remove the bridge, everything still works (just without auto-loaded writing context).