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

393 lines
14 KiB
Markdown

---
name: colette-bridge
description: |
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:
```bash
./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:
```bash
./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
```markdown
# 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:
```bash
./lib/archeflow-event.sh "$RUN_ID" decision init "" \
'{"what":"colette_bundle_cache","chosen":"reuse","reason":"all sources older than bundle"}'
```
When regenerating:
```bash
./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:
```yaml
---
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`:
```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:
```markdown
# 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).