- skills/memory: cross-run learning from recurring findings + lib/archeflow-memory.sh - skills/convergence: oscillation detection + early termination in multi-cycle runs - skills/colette-bridge: auto-inject voice profiles, personas, characters from colette.yaml - skills/templates: workflow/team/archetype gallery with init/save/share - skills/progress: live .archeflow/progress.md during runs - skills/effectiveness: per-archetype signal-to-noise + cost efficiency scoring - skills/git-integration: auto-branch per run, commit per phase, rollback support
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 towritingautomaticallyarcheflow:artifact-routing— bundle is injected via the artifact routing systemarcheflow:run— bridge hooks into run initialization
Trigger
At run.start, after domain detection but before the Plan phase:
- Check if
colette.yamlexists in the project root - If found, activate Colette Bridge
- 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:attention-filters.
| 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:
- Reads
voice.profile: vp-giesing-gschichten-v1 - Searches for
./profiles/vp-giesing-gschichten-v1.yaml— not found - Searches for
../writing.colette/profiles/vp-giesing-gschichten-v1.yaml— found - Infers persona from voice profile ID pattern or searches
personas/— findsgiesinger.yamlat../writing.colette/personas/giesinger.yaml - Globs
characters/*.yaml— findsalex.yaml(and others if present) - Reads
CLAUDE.mdfor writing rules - 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
- Summarize, don't dump. Raw YAML wastes tokens and confuses agents. The bundle is a curated briefing.
- Cache aggressively. Voice profiles and characters rarely change mid-run. Only regenerate when mtimes change.
- 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.
- Graceful degradation. Missing files are warned about, not fatal. A project with
colette.yamlbut no characters/ still works — the Characters section is simply empty. - One bundle, filtered views. Generate the full bundle once. Filter at injection time per archetype. This keeps caching simple.
- 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).