Compare commits
9 Commits
d94688ca1b
...
feat/bats-
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a49c21bbe | |||
| 6bae80b874 | |||
| 43a147676e | |||
| 14d70689ce | |||
| 130c04fa58 | |||
| 752177528f | |||
| a1667633ad | |||
| 8837a359ac | |||
| af1f4e7da7 |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "archeflow",
|
"name": "archeflow",
|
||||||
"description": "Multi-agent orchestration with Jungian archetypes. PDCA quality cycles, shadow detection, git worktree isolation. Zero dependencies — works with any Claude Code session.",
|
"description": "Multi-agent orchestration with Jungian archetypes. PDCA quality cycles, shadow detection, git worktree isolation. Zero dependencies — works with any Claude Code session.",
|
||||||
"version": "0.7.0",
|
"version": "0.8.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Chris Nennemann"
|
"name": "Chris Nennemann"
|
||||||
},
|
},
|
||||||
@@ -14,12 +14,12 @@
|
|||||||
"shadow-detection", "workflows"
|
"shadow-detection", "workflows"
|
||||||
],
|
],
|
||||||
"skills": [
|
"skills": [
|
||||||
"run", "orchestration", "plan-phase", "do-phase", "check-phase", "act-phase",
|
"run", "sprint", "review", "check-phase", "act-phase",
|
||||||
"shadow-detection", "attention-filters", "convergence", "artifact-routing",
|
"shadow-detection", "memory", "progress", "presence",
|
||||||
"process-log", "memory", "effectiveness", "progress",
|
"colette-bridge", "git-integration", "multi-project", "cost-tracking",
|
||||||
"colette-bridge", "git-integration", "multi-project",
|
"custom-archetypes", "workflow-design", "domains",
|
||||||
"custom-archetypes", "workflow-design", "domains", "cost-tracking",
|
"templates", "autonomous-mode", "using-archeflow",
|
||||||
"templates", "autonomous-mode", "using-archeflow", "presence"
|
"af-status", "af-score", "af-dag", "af-report"
|
||||||
],
|
],
|
||||||
"hooks": "hooks/hooks.json"
|
"hooks": "hooks/hooks.json"
|
||||||
}
|
}
|
||||||
|
|||||||
168
CLAUDE.md
168
CLAUDE.md
@@ -1,71 +1,119 @@
|
|||||||
# archeflow — Multi-Agent Orchestration Plugin for Claude Code
|
# archeflow — Multi-Agent Orchestration Plugin for Claude Code
|
||||||
|
|
||||||
Workspace-level orchestration: parallel agent teams across project portfolios, PDCA cycles with Jungian archetype roles, sprint runner, and post-implementation review. Installed as a Claude Code plugin.
|
PDCA quality cycles with Jungian archetype roles, corrective action framework, sprint runner, and post-implementation review. Zero dependencies — pure Bash + Markdown.
|
||||||
|
|
||||||
## Tech Stack
|
|
||||||
|
|
||||||
- **Runtime:** Bash (lib scripts) + Claude Code skill system (Markdown skills)
|
|
||||||
- **No build step, no dependencies** — pure bash + markdown
|
|
||||||
- **Plugin format:** Claude Code plugin (skills/, hooks/, agents/, templates/)
|
|
||||||
|
|
||||||
## Key Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Use via Claude Code slash commands:
|
|
||||||
/af-sprint # Main mode: work the queue across projects
|
|
||||||
/af-run <task> # Deep orchestration with PDCA cycles
|
|
||||||
/af-review # Post-implementation security/quality review
|
|
||||||
/af-status # Current run status
|
|
||||||
/af-init # Initialize ArcheFlow in a project
|
|
||||||
/af-score # Archetype effectiveness scores
|
|
||||||
/af-memory # Cross-run lesson memory
|
|
||||||
/af-report # Full process report
|
|
||||||
/af-fanout # Colette book fanout via agents
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
skills/ Slash command implementations (one dir per skill)
|
skills/ Slash commands and internal protocols (one SKILL.md per dir)
|
||||||
sprint/ /af-sprint — queue-driven parallel agent runner
|
run/ /af-run — self-contained PDCA orchestration (core skill)
|
||||||
run/ /af-run — PDCA orchestration
|
sprint/ /af-sprint — queue-driven parallel agent dispatch
|
||||||
review/ /af-review — Guardian-led code review
|
review/ /af-review — Guardian-led code review
|
||||||
plan-phase/ PDCA Plan phase
|
check-phase/ Shared reviewer protocol (used by run + review)
|
||||||
do-phase/ PDCA Do phase
|
act-phase/ Finding collection, fix routing, exit decisions
|
||||||
check-phase/ PDCA Check phase
|
shadow-detection/ Corrective action framework (archetype + system + policy)
|
||||||
act-phase/ PDCA Act phase
|
memory/ Cross-run lessons learned
|
||||||
memory/ Cross-run lessons learned
|
cost-tracking/ Token/cost awareness and budget enforcement
|
||||||
cost-tracking/ Token/cost awareness
|
domains/ Domain detection (code, writing, research)
|
||||||
domains/ Domain detection (code, writing, research)
|
colette-bridge/ Writing context loader from colette.yaml
|
||||||
... ~25 skill directories
|
multi-project/ Cross-repo orchestration with dependency DAG
|
||||||
hooks/
|
git-integration/ Per-phase commits, branch strategy, rollback
|
||||||
hooks.json Hook definitions
|
templates/ Workflow/team bundle gallery
|
||||||
session-start/ Auto-activation on session start
|
autonomous-mode/ Unattended session protocol
|
||||||
agents/ Archetype agent definitions
|
using-archeflow/ Session-start activation (auto-loaded via hook)
|
||||||
explorer.md Divergent thinking, research
|
agents/ Archetype personality definitions (one .md per archetype)
|
||||||
creator.md Design, architecture
|
lib/ Bash helper scripts (events, git, memory, progress, etc.)
|
||||||
maker.md Implementation
|
hooks/ Session-start hook (injects using-archeflow)
|
||||||
guardian.md Security, risk, quality gates
|
templates/bundles/ Pre-configured workflow bundles
|
||||||
sage.md Wisdom, patterns, trade-offs
|
|
||||||
skeptic.md Devil's advocate
|
|
||||||
trickster.md Edge cases, unconventional approaches
|
|
||||||
lib/ Bash helper scripts (git, DAG, events, progress, etc.)
|
|
||||||
templates/bundles/ Pre-configured workflow bundles
|
|
||||||
docs/ Roadmap, dogfood notes, test reports
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Domain Rules
|
## Commands
|
||||||
|
|
||||||
- Skills are Markdown files with frontmatter — follow existing skill format exactly
|
| Command | Purpose |
|
||||||
- Agents are archetype personas — maintain their distinct voice and perspective
|
|---------|---------|
|
||||||
- Dogfood observations go to `archeflow/.archeflow/memory/lessons.jsonl`
|
| `/af-run <task>` | PDCA orchestration with full agent cycle |
|
||||||
- Cost tracking: prefer cheap models for bulk ops, expensive for creative/review
|
| `/af-sprint` | Work the queue across projects |
|
||||||
- PDCA cycle order is mandatory: Plan -> Do -> Check -> Act
|
| `/af-review` | Review existing code changes |
|
||||||
|
| `/af-status` | Current/last run status |
|
||||||
|
| `/af-init` | Initialize ArcheFlow in a project |
|
||||||
|
| `/af-score` | Archetype effectiveness scores |
|
||||||
|
| `/af-memory` | Cross-run lesson memory |
|
||||||
|
| `/af-report` | Full process report |
|
||||||
|
| `/af-fanout` | Colette book fanout via agents |
|
||||||
|
|
||||||
## Do NOT
|
## Core Concepts
|
||||||
|
|
||||||
- Add runtime dependencies — this must stay zero-dependency
|
### PDCA Cycle
|
||||||
- Change archetype personalities without updating all referencing skills
|
```
|
||||||
- Skip the Check phase in PDCA cycles (quality gate)
|
Plan (Explorer + Creator) -> Do (Maker in worktree) -> Check (Guardian first, then others) -> Act (fix, merge, or cycle)
|
||||||
- Modify hooks.json format without testing plugin reload
|
```
|
||||||
- Use ArcheFlow to orchestrate simple single-file tasks (overhead not justified)
|
|
||||||
|
### Archetypes
|
||||||
|
Explorer (research), Creator (design), Maker (implement), Guardian (security), Skeptic (assumptions), Trickster (edge cases), Sage (quality). Each has a virtue and a shadow — see `shadow-detection` skill.
|
||||||
|
|
||||||
|
### Corrective Action Framework
|
||||||
|
Three layers, one escalation protocol:
|
||||||
|
- **Archetype shadows** — individual agent dysfunction
|
||||||
|
- **System shadows** — orchestration-level issues (echo chamber, tunnel vision, scope creep)
|
||||||
|
- **Policy boundaries** — operational limits (checkpoints, budgets, circuit breakers)
|
||||||
|
|
||||||
|
### Workflows
|
||||||
|
| Risk Level | Workflow | Agents |
|
||||||
|
|------------|----------|--------|
|
||||||
|
| Low | `fast` | Creator -> Maker -> Guardian |
|
||||||
|
| Medium | `standard` | Explorer + Creator -> Maker -> Guardian + Skeptic + Sage |
|
||||||
|
| High | `thorough` | Explorer + Creator -> Maker -> All 4 reviewers |
|
||||||
|
|
||||||
|
## Guardrails
|
||||||
|
|
||||||
|
### DO
|
||||||
|
|
||||||
|
- Keep skills self-contained. The `run` skill needs zero prerequisites — it was consolidated for a reason.
|
||||||
|
- Write skills as operational instructions Claude can follow, not software specifications.
|
||||||
|
- Use tables for reference data, numbered steps for protocols.
|
||||||
|
- Emit events via `./lib/archeflow-event.sh` — but never let logging block orchestration.
|
||||||
|
- Maintain the corrective action framework when adding new agent types.
|
||||||
|
- Test skill changes by running `/af-run --dry-run` and verifying the flow.
|
||||||
|
- Keep archetype personalities distinct — each agent definition in `agents/` has a specific voice.
|
||||||
|
|
||||||
|
### DO NOT
|
||||||
|
|
||||||
|
- **Add runtime dependencies.** This must stay zero-dependency (Bash + Markdown only).
|
||||||
|
- **Bloat skills back up.** The consolidation from 27 to ~15 skills was intentional. Do not create new skills for internal implementation details — inline them.
|
||||||
|
- **Write bash pseudo-code in skills.** Skills are Claude instructions, not shell scripts. Use one-liner commands or lib script references, not multi-line bash blocks.
|
||||||
|
- **Duplicate protocol definitions.** Finding format lives in `check-phase`. Routing table lives in `act-phase`. Shadow detection lives in `shadow-detection`. One source of truth per concept.
|
||||||
|
- **Skip the Check phase** in PDCA cycles. It's the quality gate.
|
||||||
|
- **Change archetype personalities** without updating all referencing skills and agent definitions.
|
||||||
|
- **Use ArcheFlow for trivial tasks.** Single-file fixes, config changes, questions — just do them directly.
|
||||||
|
- **Let skills exceed ~200 lines.** If a skill is growing past this, it probably needs splitting or the content belongs in a lib script.
|
||||||
|
|
||||||
|
### Skill Writing Rules
|
||||||
|
|
||||||
|
1. **Frontmatter**: `name` (kebab-case), `description` (one-liner + `<example>` tags for user-invocable skills)
|
||||||
|
2. **Structure**: Imperative voice. Lead with what to do, not why. Tables > prose. Steps > paragraphs.
|
||||||
|
3. **Agent templates**: Keep Agent() spawn templates concise. Include only the prompt, subagent_type, and isolation mode.
|
||||||
|
4. **Cross-references**: Use `archeflow:<skill-name>` backtick syntax to reference other skills. Avoid circular dependencies.
|
||||||
|
5. **Bash commands**: One-liners only in skills. Multi-step logic belongs in `lib/` scripts.
|
||||||
|
|
||||||
|
### Cost Awareness
|
||||||
|
|
||||||
|
- Prefer cheap models (haiku) for analytical tasks (validation, diff scoring)
|
||||||
|
- Use capable models (sonnet/opus) for creative tasks (writing, complex design)
|
||||||
|
- Budget enforcement via `cost-tracking` skill and `.archeflow/config.yaml`
|
||||||
|
- Track token spend per agent in events for post-run analysis
|
||||||
|
|
||||||
|
### Git Rules
|
||||||
|
|
||||||
|
- Signing: `git config gpg.format ssh`, key at `~/.ssh/id_ed25519_dev.pub`
|
||||||
|
- Push: `GIT_SSH_COMMAND="ssh -i /home/c/.ssh/id_ed25519_dev -o IdentitiesOnly=yes" git push origin main`
|
||||||
|
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
||||||
|
- No Co-Authored-By trailers
|
||||||
|
- All work on worktree branches until explicitly merged
|
||||||
|
- Merges use `--no-ff` (individually revertable)
|
||||||
|
|
||||||
|
## Dogfooding
|
||||||
|
|
||||||
|
When using ArcheFlow to develop ArcheFlow itself:
|
||||||
|
- Log observations to `.archeflow/memory/lessons.jsonl`
|
||||||
|
- Note friction points, shadow false positives, skill gaps
|
||||||
|
- Test skill changes with `/af-run --dry-run` before committing
|
||||||
|
|||||||
89
README.md
89
README.md
@@ -146,61 +146,51 @@ Shadow detection is quantitative, not vibes. Explorer output exceeding 2000 word
|
|||||||
|
|
||||||
## Skills Reference
|
## Skills Reference
|
||||||
|
|
||||||
ArcheFlow ships with 24 skills organized by function.
|
ArcheFlow ships with 19 skills organized by function. The `run` skill is self-contained -- no prerequisites needed.
|
||||||
|
|
||||||
### Core Orchestration
|
### Core Orchestration
|
||||||
|
|
||||||
| Skill | Description |
|
| Skill | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| `archeflow:run` | Automated PDCA execution loop -- single-command orchestration with `--start-from`, `--dry-run`, and cycle-back |
|
| `archeflow:run` | Self-contained PDCA orchestration -- Plan/Do/Check/Act with adaptation rules, pipeline strategy, and cycle-back |
|
||||||
| `archeflow:orchestration` | Step-by-step PDCA execution guide for manual orchestration |
|
| `archeflow:sprint` | Queue-driven parallel agent dispatch across projects (primary mode) |
|
||||||
| `archeflow:plan-phase` | Explorer and Creator output formats and protocols |
|
| `archeflow:review` | Guardian-led code review on diff/branch/commit range |
|
||||||
| `archeflow:do-phase` | Maker implementation rules and worktree commit strategy |
|
| `archeflow:check-phase` | Shared reviewer protocol -- finding format, evidence requirements, attention filters |
|
||||||
| `archeflow:check-phase` | Shared reviewer protocols and output format |
|
| `archeflow:act-phase` | Finding collection, fix routing, exit decisions |
|
||||||
| `archeflow:act-phase` | Post-Check decision logic: collect findings, route fixes, exit or cycle |
|
|
||||||
|
|
||||||
### Quality and Safety
|
### Quality and Safety
|
||||||
|
|
||||||
| Skill | Description |
|
| Skill | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| `archeflow:shadow-detection` | Quantitative dysfunction detection and automatic correction |
|
| `archeflow:shadow-detection` | Corrective action framework -- archetype shadows, system shadows, policy boundaries |
|
||||||
| `archeflow:attention-filters` | Context optimization per archetype -- each agent gets only what it needs |
|
|
||||||
| `archeflow:convergence` | Detects convergence, stalling, and oscillation in multi-cycle runs |
|
|
||||||
| `archeflow:artifact-routing` | Inter-phase artifact protocol -- naming, storage, routing, archiving |
|
|
||||||
|
|
||||||
### Process Intelligence
|
|
||||||
|
|
||||||
| Skill | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `archeflow:process-log` | Event-sourced JSONL logging with DAG parent relationships |
|
|
||||||
| `archeflow:memory` | Cross-run memory that learns recurring findings and injects lessons |
|
| `archeflow:memory` | Cross-run memory that learns recurring findings and injects lessons |
|
||||||
| `archeflow:effectiveness` | Archetype scoring on signal-to-noise, fix rate, cost efficiency |
|
|
||||||
| `archeflow:progress` | Live progress file watchable from a second terminal |
|
|
||||||
|
|
||||||
### Integration
|
### Integration
|
||||||
|
|
||||||
| Skill | Description |
|
| Skill | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| `archeflow:colette-bridge` | Bridges ArcheFlow with the Colette writing platform |
|
| `archeflow:colette-bridge` | Bridges ArcheFlow with the Colette writing platform |
|
||||||
| `archeflow:git-integration` | Git-per-phase commits, branch-per-run, rollback to any phase boundary |
|
| `archeflow:git-integration` | Per-phase commits, branch-per-run, rollback |
|
||||||
| `archeflow:multi-project` | Cross-repo orchestration with dependency DAG and shared budget |
|
| `archeflow:multi-project` | Cross-repo orchestration with dependency DAG and shared budget |
|
||||||
|
| `archeflow:cost-tracking` | Budget enforcement, per-agent cost aggregation, model tier recommendations |
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
| Skill | Description |
|
| Skill | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
|
| `archeflow:domains` | Domain adapters for writing, research, and non-code workflows |
|
||||||
| `archeflow:custom-archetypes` | Create domain-specific roles (database reviewer, compliance auditor, etc.) |
|
| `archeflow:custom-archetypes` | Create domain-specific roles (database reviewer, compliance auditor, etc.) |
|
||||||
| `archeflow:workflow-design` | Design custom workflows with per-phase archetype assignment and exit conditions |
|
| `archeflow:workflow-design` | Design custom workflows with per-phase archetype assignment |
|
||||||
| `archeflow:domains` | Domain adapters for writing, research, and other non-code workflows |
|
|
||||||
| `archeflow:cost-tracking` | Budget enforcement, per-agent cost aggregation, model tier recommendations |
|
|
||||||
| `archeflow:templates` | Template gallery for sharing workflows, teams, and setup bundles |
|
| `archeflow:templates` | Template gallery for sharing workflows, teams, and setup bundles |
|
||||||
| `archeflow:autonomous-mode` | Unattended overnight sessions with progress logging and safe stopping |
|
| `archeflow:autonomous-mode` | Unattended sessions with corrective action checkpoints |
|
||||||
|
| `archeflow:progress` | Live progress file watchable from a second terminal |
|
||||||
|
| `archeflow:presence` | User-facing output format -- show outcomes, not mechanics |
|
||||||
|
|
||||||
### Meta
|
### Meta
|
||||||
|
|
||||||
| Skill | Description |
|
| Skill | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| `archeflow:using-archeflow` | Session-start skill -- activation criteria, workflow selection, quick reference |
|
| `archeflow:using-archeflow` | Session-start activation -- decision tree, workflow selection, commands |
|
||||||
|
|
||||||
## Library Scripts
|
## Library Scripts
|
||||||
|
|
||||||
@@ -341,47 +331,28 @@ archetypes: [explorer, creator, maker, guardian, db-specialist]
|
|||||||
|
|
||||||
```
|
```
|
||||||
archeflow/
|
archeflow/
|
||||||
├── .claude-plugin/plugin.json # Plugin manifest (v0.5.0)
|
├── .claude-plugin/plugin.json # Plugin manifest
|
||||||
├── agents/ # 7 archetype personas (behavioral protocols)
|
├── agents/ # 7 archetype personas (behavioral protocols)
|
||||||
│ ├── explorer.md # Plan: research and context mapping
|
│ ├── explorer.md, creator.md # Plan phase agents
|
||||||
│ ├── creator.md # Plan: solution design and proposals
|
│ ├── maker.md # Do phase agent
|
||||||
│ ├── maker.md # Do: implementation in isolated worktree
|
│ └── guardian.md, skeptic.md, # Check phase agents
|
||||||
│ ├── guardian.md # Check: security and reliability review
|
│ trickster.md, sage.md
|
||||||
│ ├── skeptic.md # Check: assumption challenging
|
├── skills/ # 19 skills (consolidated from 27)
|
||||||
│ ├── trickster.md # Check: adversarial testing
|
│ ├── run/ # Self-contained PDCA orchestration (core)
|
||||||
│ └── sage.md # Check: holistic quality review
|
│ ├── sprint/ # Queue-driven parallel agent dispatch
|
||||||
├── skills/ # 24 behavioral skills
|
│ ├── review/ # Guardian-led code review
|
||||||
│ ├── run/ # Automated PDCA loop
|
│ ├── check-phase/ # Shared reviewer protocol + attention filters
|
||||||
│ ├── orchestration/ # Manual PDCA execution guide
|
│ ├── act-phase/ # Finding collection + fix routing
|
||||||
│ ├── plan-phase/ # Plan protocols
|
│ ├── shadow-detection/ # Corrective action framework (3 layers)
|
||||||
│ ├── do-phase/ # Do protocols
|
|
||||||
│ ├── check-phase/ # Check protocols
|
|
||||||
│ ├── act-phase/ # Act phase decision logic
|
|
||||||
│ ├── shadow-detection/ # Dysfunction detection
|
|
||||||
│ ├── attention-filters/ # Context optimization
|
|
||||||
│ ├── convergence/ # Cycle convergence detection
|
|
||||||
│ ├── artifact-routing/ # Inter-phase artifact protocol
|
|
||||||
│ ├── process-log/ # Event-sourced JSONL logging
|
|
||||||
│ ├── memory/ # Cross-run learning
|
│ ├── memory/ # Cross-run learning
|
||||||
│ ├── effectiveness/ # Archetype scoring
|
│ └── ... # + 12 config/integration skills
|
||||||
│ ├── progress/ # Live progress file
|
├── lib/ # 10 shell scripts (events, git, memory, etc.)
|
||||||
│ ├── colette-bridge/ # Colette writing platform bridge
|
|
||||||
│ ├── git-integration/ # Per-phase git commits
|
|
||||||
│ ├── multi-project/ # Cross-repo orchestration
|
|
||||||
│ ├── custom-archetypes/ # Domain-specific roles
|
|
||||||
│ ├── workflow-design/ # Custom workflow design
|
|
||||||
│ ├── domains/ # Domain adapters
|
|
||||||
│ ├── cost-tracking/ # Budget and cost management
|
|
||||||
│ ├── templates/ # Template gallery
|
|
||||||
│ ├── autonomous-mode/ # Unattended sessions
|
|
||||||
│ └── using-archeflow/ # Session-start activation
|
|
||||||
├── lib/ # 8 shell scripts (process infrastructure)
|
|
||||||
├── hooks/ # Auto-activation (SessionStart)
|
├── hooks/ # Auto-activation (SessionStart)
|
||||||
├── examples/ # Walkthroughs, templates, custom archetypes
|
├── examples/ # Walkthroughs, templates, custom archetypes
|
||||||
└── docs/ # Roadmap, changelog
|
└── docs/ # Roadmap, changelog
|
||||||
```
|
```
|
||||||
|
|
||||||
The flow: skills define behavioral rules (what agents should do), agents define personas (how they think), lib scripts handle tooling (event logging, git, reporting), and hooks wire it all together at session start. Events are emitted at every phase transition, forming a DAG that can be rendered, reported, or scored after the run.
|
Skills define behavioral rules, agents define personas, lib scripts handle tooling, hooks wire it together at session start. The `run` skill is self-contained -- it absorbed 8 previously separate skills (orchestration, plan-phase, do-phase, artifact-routing, process-log, convergence, effectiveness, attention-filters) into one 459-line operational guide.
|
||||||
|
|
||||||
## Philosophy
|
## Philosophy
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const path = require("path");
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const pluginRoot = path.resolve(__dirname, "..");
|
const pluginRoot = path.resolve(__dirname, "..");
|
||||||
const skillFile = path.join(pluginRoot, "skills", "using-archeflow", "SKILL.md");
|
const skillFile = path.join(pluginRoot, "skills", "using-archeflow", "ACTIVATION.md");
|
||||||
|
|
||||||
if (!fs.existsSync(skillFile)) {
|
if (!fs.existsSync(skillFile)) {
|
||||||
console.log("{}");
|
console.log("{}");
|
||||||
|
|||||||
34
scripts/run-tests.sh
Executable file
34
scripts/run-tests.sh
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# run-tests.sh — Run all ArcheFlow bats tests.
|
||||||
|
#
|
||||||
|
# Usage: ./scripts/run-tests.sh [bats-args...]
|
||||||
|
# Examples:
|
||||||
|
# ./scripts/run-tests.sh # Run all tests
|
||||||
|
# ./scripts/run-tests.sh --filter "event" # Run only event tests
|
||||||
|
# ./scripts/run-tests.sh -t # TAP output
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
TESTS_DIR="$PROJECT_DIR/tests"
|
||||||
|
|
||||||
|
# Find bats binary
|
||||||
|
BATS="${BATS:-}"
|
||||||
|
if [[ -z "$BATS" ]]; then
|
||||||
|
if command -v bats &>/dev/null; then
|
||||||
|
BATS="bats"
|
||||||
|
elif [[ -x "$HOME/.local/bin/bats" ]]; then
|
||||||
|
BATS="$HOME/.local/bin/bats"
|
||||||
|
else
|
||||||
|
echo "ERROR: bats not found. Install bats-core or set BATS env var." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Running ArcheFlow tests..."
|
||||||
|
echo " bats: $($BATS --version)"
|
||||||
|
echo " tests: $TESTS_DIR"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
exec "$BATS" "$@" "$TESTS_DIR"/*.bats
|
||||||
@@ -1,292 +1,46 @@
|
|||||||
---
|
---
|
||||||
name: act-phase
|
name: act-phase
|
||||||
description: |
|
description: |
|
||||||
Use after the Check phase completes. Collects reviewer findings, prioritizes them, routes fixes to the right agent or tool, applies fixes systematically, and decides whether to exit or cycle.
|
Use after the Check phase completes. Collects reviewer findings, routes fixes, applies them, decides whether to exit or cycle.
|
||||||
<example>Automatically loaded during orchestration after Check phase</example>
|
<example>Automatically loaded during orchestration after Check phase</example>
|
||||||
<example>User: "Run just the act phase on existing findings"</example>
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Act Phase
|
# Act Phase
|
||||||
|
|
||||||
After all reviewers complete, the Act phase turns findings into fixes and decides whether the cycle is done. This is the bridge between "what's wrong" and "what we do about it."
|
Turn Check phase findings into fixes, then decide: exit or cycle.
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
```
|
```
|
||||||
Check phase output → Collect → Prioritize → Route → Fix → Verify → Exit or Cycle
|
Check output → Collect → Deduplicate → Route → Fix → Exit or Cycle
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 1: Finding Collection
|
## Step 1: Collect and Consolidate Findings
|
||||||
|
|
||||||
Parse all reviewer outputs into one consolidated findings table. Use the standardized format from the `check-phase` skill.
|
Parse all reviewer outputs into one table grouped by severity (CRITICAL / WARNING / INFO):
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Findings Summary — Cycle N
|
|
||||||
|
|
||||||
### CRITICAL (must fix before next cycle)
|
|
||||||
| # | Source | Location | Category | Description | Suggested Fix |
|
| # | Source | Location | Category | Description | Suggested Fix |
|
||||||
|---|--------|----------|----------|-------------|---------------|
|
|---|--------|----------|----------|-------------|---------------|
|
||||||
| 1 | guardian | src/auth/handler.ts:48 | security | Empty string bypasses validation | Add length check |
|
| 1 | guardian | src/auth/handler.ts:48 | security | Empty string bypasses validation | Add length check |
|
||||||
| 2 | trickster | src/api/parse.ts:92 | reliability | Null input causes crash | Guard with null check |
|
|
||||||
|
|
||||||
### WARNING (should fix)
|
|
||||||
| # | Source | Location | Category | Description | Suggested Fix |
|
|
||||||
|---|--------|----------|----------|-------------|---------------|
|
|
||||||
| 3 | sage | tests/auth.test.ts:15 | testing | Test names don't describe behavior | Rename to "should reject expired tokens" |
|
|
||||||
| 4 | guardian | src/auth/handler.ts:52 | security | Missing rate limit | Add rate limiter middleware |
|
|
||||||
|
|
||||||
### INFO (nice to have)
|
|
||||||
| # | Source | Location | Category | Description | Suggested Fix |
|
|
||||||
|---|--------|----------|----------|-------------|---------------|
|
|
||||||
| 5 | skeptic | src/auth/handler.ts:30 | design | Consider caching validated tokens | Add TTL cache |
|
|
||||||
```
|
|
||||||
|
|
||||||
### Deduplication
|
### Deduplication
|
||||||
|
|
||||||
Before listing findings, deduplicate across reviewers (same rule as `check-phase`):
|
Same file + same category + similar description = one finding. Use the higher severity, credit all sources (e.g. `guardian + skeptic`).
|
||||||
- Same file + same category + similar description = one finding
|
|
||||||
- Use the higher severity
|
|
||||||
- Credit all sources: `guardian + skeptic`
|
|
||||||
- Don't double-count in severity tallies
|
|
||||||
|
|
||||||
### Cross-Cycle Tracking
|
### Cross-Cycle Tracking (cycle > 1)
|
||||||
|
|
||||||
Compare against prior cycle findings (if cycle > 1):
|
Compare against prior cycle findings:
|
||||||
- **Resolved:** Finding from cycle N-1 no longer present → mark resolved, do not re-raise
|
- **Resolved** — no longer present, mark resolved, do not re-raise
|
||||||
- **Persisting:** Same location + category still present → increment `cycle_count`
|
- **Persisting** — same location + category, increment `cycle_count`
|
||||||
- **New:** Finding not seen before → add with `cycle_count: 1`
|
- **New** — first appearance, `cycle_count: 1`
|
||||||
|
|
||||||
If a finding persists for 2+ consecutive cycles, flag for user escalation (see Step 5).
|
Finding persisting 2+ cycles = flag for escalation (see Step 4).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 2: Fix Routing
|
## Step 2: Fix Routing
|
||||||
|
|
||||||
Not all findings are fixed the same way. Route each finding based on its nature:
|
This is the **canonical routing table** (single source of truth for the whole system):
|
||||||
|
|
||||||
| Category | Fix Route | Rationale |
|
|
||||||
|----------|-----------|-----------|
|
|
||||||
| `security` | Spawn Maker with targeted instructions | Security fixes need tested code changes |
|
|
||||||
| `reliability` | Spawn Maker with targeted instructions | Same — code-level fix with test |
|
|
||||||
| `breaking-change` | Route to Creator in next cycle | Design decision needed |
|
|
||||||
| `design` | Route to Creator in next cycle | Architecture change, not a patch |
|
|
||||||
| `dependency` | Spawn Maker with targeted instructions | Package update or removal |
|
|
||||||
| `quality` | Spawn Maker or apply directly | Depends on scope (see below) |
|
|
||||||
| `testing` | Spawn Maker with targeted instructions | Tests need to be written and run |
|
|
||||||
| `consistency` | Apply directly or spawn Maker | Naming/style → direct. Pattern change → Maker |
|
|
||||||
|
|
||||||
### Direct Fix (no agent)
|
|
||||||
|
|
||||||
Apply directly with Edit tool when **all** of these are true:
|
|
||||||
- The fix is mechanical (typo, naming, formatting, import order)
|
|
||||||
- No behavioral change
|
|
||||||
- No test update needed
|
|
||||||
- Exactly one file affected
|
|
||||||
|
|
||||||
Examples: rename a variable, fix a typo in a string, reorder imports, fix indentation.
|
|
||||||
|
|
||||||
### Maker Fix (spawn agent)
|
|
||||||
|
|
||||||
Spawn a targeted Maker when the fix involves:
|
|
||||||
- Code logic changes
|
|
||||||
- New or modified tests
|
|
||||||
- Multiple files
|
|
||||||
- Any behavioral change
|
|
||||||
|
|
||||||
Provide the Maker with:
|
|
||||||
1. The specific finding(s) to address (not all findings — just the routed ones)
|
|
||||||
2. The file and line location
|
|
||||||
3. The suggested fix from the reviewer
|
|
||||||
4. The Maker's original branch (to apply fixes on top)
|
|
||||||
|
|
||||||
```
|
|
||||||
Agent(
|
|
||||||
description: "Fix: <finding description>",
|
|
||||||
prompt: "You are the MAKER archetype.
|
|
||||||
Apply this fix on branch: <maker's branch>
|
|
||||||
|
|
||||||
Finding: <source> | <severity> | <category>
|
|
||||||
Location: <file:line>
|
|
||||||
Issue: <description>
|
|
||||||
Suggested fix: <fix>
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
1. Fix ONLY this issue — no other changes
|
|
||||||
2. Add/update tests if the fix changes behavior
|
|
||||||
3. Run existing tests — nothing may break
|
|
||||||
4. Commit with message: 'fix: <description>'
|
|
||||||
Do NOT refactor surrounding code.",
|
|
||||||
isolation: "worktree",
|
|
||||||
mode: "bypassPermissions"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Writing/Prose Fix (domain-specific)
|
|
||||||
|
|
||||||
For writing projects (books, stories), voice or prose findings need special context:
|
|
||||||
|
|
||||||
```
|
|
||||||
Agent(
|
|
||||||
description: "Fix: voice drift in <file>",
|
|
||||||
prompt: "You are the MAKER archetype.
|
|
||||||
Apply this prose fix on branch: <maker's branch>
|
|
||||||
|
|
||||||
Finding: <source> | <severity> | <category>
|
|
||||||
Location: <file:line>
|
|
||||||
Issue: <description>
|
|
||||||
|
|
||||||
Voice profile to match: <load from .archeflow/config.yaml or project voice profile>
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
1. Fix the flagged passage to match the voice profile
|
|
||||||
2. Do not rewrite surrounding paragraphs
|
|
||||||
3. Preserve the narrative intent — only change voice/style
|
|
||||||
4. Commit with message: 'fix: <description>'",
|
|
||||||
isolation: "worktree",
|
|
||||||
mode: "bypassPermissions"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Design Fix (route to next cycle)
|
|
||||||
|
|
||||||
Findings that require design changes are NOT fixed in the Act phase. They become structured feedback for the Creator in the next PDCA cycle. Collect them into `act-feedback.md` (see Step 5).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 3: Fix Application Protocol
|
|
||||||
|
|
||||||
Apply fixes in severity order: CRITICAL first, then WARNING, then INFO. Within the same severity, fix in file order (reduces context switching).
|
|
||||||
|
|
||||||
### For each fix:
|
|
||||||
|
|
||||||
1. **Apply the change** (direct edit or via Maker agent)
|
|
||||||
2. **Emit `fix.applied` event:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "fix.applied",
|
|
||||||
"phase": "act",
|
|
||||||
"agent": "maker",
|
|
||||||
"data": {
|
|
||||||
"source": "guardian",
|
|
||||||
"finding": "Empty string bypasses validation",
|
|
||||||
"file": "src/auth/handler.ts",
|
|
||||||
"line": 48,
|
|
||||||
"severity": "CRITICAL",
|
|
||||||
"before": "<old code>",
|
|
||||||
"after": "<new code>"
|
|
||||||
},
|
|
||||||
"parent": [<seq of the review.verdict that found it>]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
3. **Targeted re-check** (if the fix is non-trivial):
|
|
||||||
- Re-run only the reviewer that raised the finding
|
|
||||||
- Scope the re-check to just the changed file(s)
|
|
||||||
- If the re-check raises new findings → add them to the findings list with source `re-check:<reviewer>`
|
|
||||||
|
|
||||||
### Batching Maker Fixes
|
|
||||||
|
|
||||||
If multiple findings route to the same Maker and affect the same file or tightly coupled files, batch them into a single Maker spawn:
|
|
||||||
|
|
||||||
```
|
|
||||||
Agent(
|
|
||||||
description: "Fix: 3 findings in src/auth/",
|
|
||||||
prompt: "You are the MAKER archetype.
|
|
||||||
Apply these fixes on branch: <maker's branch>
|
|
||||||
|
|
||||||
1. [CRITICAL] src/auth/handler.ts:48 — Empty string bypass → Add length check
|
|
||||||
2. [WARNING] src/auth/handler.ts:52 — Missing rate limit → Add middleware
|
|
||||||
3. [WARNING] tests/auth.test.ts:15 — Bad test names → Rename to behavior descriptions
|
|
||||||
|
|
||||||
Fix all three. Commit each as a separate commit.
|
|
||||||
Run tests after all fixes."
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Batch only within the same functional area. Don't batch unrelated fixes — the Maker loses focus.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 4: Exit Decision
|
|
||||||
|
|
||||||
After all fixes are applied, evaluate exit conditions:
|
|
||||||
|
|
||||||
### Decision Tree
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─ Count remaining CRITICAL findings (including from re-checks)
|
|
||||||
│
|
|
||||||
├─ CRITICAL = 0 AND completion criteria met (if defined)
|
|
||||||
│ └─ EXIT: Proceed to merge
|
|
||||||
│
|
|
||||||
├─ CRITICAL = 0 AND completion criteria NOT met
|
|
||||||
│ └─ CYCLE: Feed back "completion criteria failing" to Creator
|
|
||||||
│
|
|
||||||
├─ CRITICAL > 0 AND cycles_remaining > 0
|
|
||||||
│ └─ CYCLE: Build feedback, go to Plan phase
|
|
||||||
│
|
|
||||||
├─ CRITICAL > 0 AND cycles_remaining = 0
|
|
||||||
│ └─ STOP: Report to user with unresolved findings
|
|
||||||
│
|
|
||||||
└─ Same CRITICAL finding persisted 2+ cycles
|
|
||||||
└─ ESCALATE: Stop and ask user for guidance
|
|
||||||
```
|
|
||||||
|
|
||||||
### Emit `cycle.boundary` event:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "cycle.boundary",
|
|
||||||
"phase": "act",
|
|
||||||
"data": {
|
|
||||||
"cycle": 1,
|
|
||||||
"max_cycles": 2,
|
|
||||||
"exit_condition": "all_approved",
|
|
||||||
"met": false,
|
|
||||||
"critical_remaining": 1,
|
|
||||||
"warning_remaining": 2,
|
|
||||||
"info_remaining": 1,
|
|
||||||
"fixes_applied": 3,
|
|
||||||
"design_issues_forwarded": 1,
|
|
||||||
"next_action": "cycle"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 5: Cycle Feedback Protocol
|
|
||||||
|
|
||||||
When cycling back, produce `act-feedback.md` as a structured handoff. This replaces dumping raw findings.
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Cycle N Feedback → Cycle N+1
|
|
||||||
|
|
||||||
### For Creator (design changes needed)
|
|
||||||
| # | Source | Severity | Category | Issue | Cycles Open |
|
|
||||||
|---|--------|----------|----------|-------|-------------|
|
|
||||||
| 1 | guardian | CRITICAL | security | SQL injection in user input | 1 |
|
|
||||||
| 2 | skeptic | WARNING | design | Assumes single-tenant only | 1 |
|
|
||||||
|
|
||||||
### For Maker (implementation fixes needed)
|
|
||||||
| # | Source | Severity | Category | Issue | Cycles Open |
|
|
||||||
|---|--------|----------|----------|-------|-------------|
|
|
||||||
| 3 | sage | WARNING | testing | Test assertions too weak | 1 |
|
|
||||||
| 4 | trickster | WARNING | reliability | Error path not tested | 1 |
|
|
||||||
|
|
||||||
### Resolved in This Cycle
|
|
||||||
| # | Source | Issue | How Resolved |
|
|
||||||
|---|--------|-------|--------------|
|
|
||||||
| 5 | guardian | Missing rate limit | Added rate limiter middleware (commit abc123) |
|
|
||||||
| 6 | sage | Test names unclear | Renamed to behavior descriptions (commit def456) |
|
|
||||||
|
|
||||||
### Persisting Issues (escalation candidates)
|
|
||||||
| # | Source | Issue | Cycles Open | Action |
|
|
||||||
|---|--------|-------|-------------|--------|
|
|
||||||
| — | — | — | — | — |
|
|
||||||
```
|
|
||||||
|
|
||||||
**Routing rules** (canonical table — matches orchestration and artifact-routing skills):
|
|
||||||
|
|
||||||
| Source | Category | Routes to | Reason |
|
| Source | Category | Routes to | Reason |
|
||||||
|--------|----------|-----------|--------|
|
|--------|----------|-----------|--------|
|
||||||
@@ -296,76 +50,91 @@ When cycling back, produce `act-feedback.md` as a structured handoff. This repla
|
|||||||
| Sage | quality, consistency | Maker | Implementation refinement |
|
| Sage | quality, consistency | Maker | Implementation refinement |
|
||||||
| Sage | testing | Maker | Test gap, not design flaw |
|
| Sage | testing | Maker | Test gap, not design flaw |
|
||||||
| Trickster | reliability (design flaw) | Creator | Needs redesign |
|
| Trickster | reliability (design flaw) | Creator | Needs redesign |
|
||||||
| Trickster | reliability (test gap) | Maker | Needs more tests |
|
| Trickster | reliability (test gap), testing | Maker | Needs more tests |
|
||||||
| Trickster | testing | Maker | Edge case not covered |
|
|
||||||
|
|
||||||
**Disambiguation rule:** When in doubt: if the fix requires changing the approach, route to Creator. If it requires changing the code within the existing approach, route to Maker.
|
**Disambiguation:** If the fix requires changing the approach → Creator. If it requires changing code within the existing approach → Maker.
|
||||||
|
|
||||||
|
### Direct Fix (no agent)
|
||||||
|
|
||||||
|
Apply with Edit tool when **all** are true:
|
||||||
|
- Mechanical (typo, naming, formatting, import order)
|
||||||
|
- No behavioral change
|
||||||
|
- No test update needed
|
||||||
|
- Single file
|
||||||
|
|
||||||
|
### Maker Fix (spawn agent)
|
||||||
|
|
||||||
|
Spawn a targeted Maker when the fix involves code logic, tests, multiple files, or behavioral changes. Batch findings in the same file area into one Maker spawn.
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent(
|
||||||
|
description: "Fix: <description>",
|
||||||
|
prompt: "You are the MAKER archetype.
|
||||||
|
Branch: <maker's branch>
|
||||||
|
Findings:
|
||||||
|
1. [CRITICAL] file:line — issue → suggested fix
|
||||||
|
2. [WARNING] file:line — issue → suggested fix
|
||||||
|
Rules: fix ONLY these issues, add/update tests if behavior changes,
|
||||||
|
run tests, commit each fix separately as 'fix: <description>'.
|
||||||
|
Do NOT refactor surrounding code.",
|
||||||
|
isolation: "worktree",
|
||||||
|
mode: "bypassPermissions"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Design Fix (route to Creator)
|
||||||
|
|
||||||
|
Design findings are NOT fixed in Act. Collect them into `act-feedback.md` for the Creator in the next cycle (see Step 5).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Step 6: Incremental Runs
|
## Step 3: Fix Application
|
||||||
|
|
||||||
Support starting the orchestration from any phase by reusing existing artifacts.
|
Apply in severity order: CRITICAL → WARNING → INFO. Within same severity, group by file.
|
||||||
|
|
||||||
### `--start-from check`
|
For each fix:
|
||||||
|
1. Apply the change (direct edit or via Maker agent)
|
||||||
Re-run Check + Act on existing Do artifacts:
|
2. Emit `fix.applied` event with source, finding, file, severity, before/after
|
||||||
1. Read `.archeflow/artifacts/<run_id>/` for Maker branch and implementation summary
|
3. For non-trivial fixes: re-run only the originating reviewer scoped to changed files. New findings from re-check get added with source `re-check:<reviewer>`
|
||||||
2. Verify the Maker branch still exists (`git branch --list`)
|
|
||||||
3. Spawn reviewers against the existing branch
|
|
||||||
4. Proceed through Act phase normally
|
|
||||||
|
|
||||||
### `--start-from act`
|
|
||||||
|
|
||||||
Re-run Act with existing Check findings:
|
|
||||||
1. Read `.archeflow/artifacts/<run_id>/` for Check phase consolidated output
|
|
||||||
2. Parse findings from the stored reviewer outputs
|
|
||||||
3. Skip finding collection (already done) — proceed from Step 2 (Fix Routing)
|
|
||||||
|
|
||||||
### `--start-from do`
|
|
||||||
|
|
||||||
Re-run Do + Check + Act with existing Plan:
|
|
||||||
1. Read `.archeflow/artifacts/<run_id>/` for Creator's proposal
|
|
||||||
2. Verify proposal exists and is parseable
|
|
||||||
3. Spawn Maker with the existing proposal
|
|
||||||
4. Proceed through Check and Act normally
|
|
||||||
|
|
||||||
### Artifact Verification
|
|
||||||
|
|
||||||
Before starting from a mid-point, verify required artifacts exist:
|
|
||||||
|
|
||||||
```
|
|
||||||
--start-from do → needs: proposal (Creator output)
|
|
||||||
--start-from check → needs: proposal + implementation (Maker branch + summary)
|
|
||||||
--start-from act → needs: proposal + implementation + review outputs
|
|
||||||
```
|
|
||||||
|
|
||||||
If artifacts are missing, report which ones and abort. Don't guess or generate placeholders.
|
|
||||||
|
|
||||||
### Event Continuity
|
|
||||||
|
|
||||||
For incremental runs, emit events with `parent` pointing to the existing artifacts' events:
|
|
||||||
1. Read the existing `<run_id>.jsonl` to find the last `seq` number
|
|
||||||
2. Continue sequence numbering from there
|
|
||||||
3. Set `parent` on the first new event to point to the last event of the prior phase
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Act Phase Checklist (Quick Reference)
|
## Step 4: Exit Decision
|
||||||
|
|
||||||
```
|
```
|
||||||
□ Parse all reviewer outputs into consolidated findings table
|
CRITICAL = 0 AND criteria met → EXIT: proceed to merge
|
||||||
□ Deduplicate across reviewers
|
CRITICAL = 0 AND criteria NOT met → CYCLE: feedback to Creator
|
||||||
□ Compare against prior cycle findings (if cycle > 1)
|
CRITICAL > 0 AND cycles remaining → CYCLE: build feedback, go to Plan
|
||||||
□ Route each finding: direct fix / Maker / Creator feedback
|
CRITICAL > 0 AND no cycles left → STOP: report unresolved to user
|
||||||
□ Apply direct fixes first (fastest)
|
Same CRITICAL persists 2+ cycles → ESCALATE: ask user for guidance
|
||||||
□ Spawn Maker(s) for code fixes (batch by file area)
|
|
||||||
□ Emit fix.applied event for each fix
|
|
||||||
□ Re-check non-trivial fixes with the originating reviewer
|
|
||||||
□ Count remaining CRITICALs after all fixes
|
|
||||||
□ Check completion criteria (if defined)
|
|
||||||
□ Decide: exit / cycle / escalate
|
|
||||||
□ If cycling: produce act-feedback.md with routed findings
|
|
||||||
□ If exiting: proceed to merge (see orchestration skill Step 4)
|
|
||||||
□ Emit cycle.boundary event
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Emit `cycle.boundary` event with: cycle number, max_cycles, critical/warning/info remaining, fixes applied, next action.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Cycle Feedback
|
||||||
|
|
||||||
|
When cycling back, produce `act-feedback.md`:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Cycle N → Cycle N+1
|
||||||
|
|
||||||
|
### For Creator (design changes needed)
|
||||||
|
| # | Source | Severity | Category | Issue | Cycles Open |
|
||||||
|
|---|--------|----------|----------|-------|-------------|
|
||||||
|
|
||||||
|
### For Maker (implementation fixes needed)
|
||||||
|
| # | Source | Severity | Category | Issue | Cycles Open |
|
||||||
|
|---|--------|----------|----------|-------|-------------|
|
||||||
|
|
||||||
|
### Resolved This Cycle
|
||||||
|
| # | Source | Issue | How Resolved |
|
||||||
|
|---|--------|-------|--------------|
|
||||||
|
|
||||||
|
### Persisting Issues (escalation candidates)
|
||||||
|
| # | Source | Issue | Cycles Open | Action |
|
||||||
|
|---|--------|-------|-------------|--------|
|
||||||
|
```
|
||||||
|
|
||||||
|
Route findings into Creator vs Maker sections using the routing table in Step 2.
|
||||||
|
|||||||
34
skills/af-dag/SKILL.md
Normal file
34
skills/af-dag/SKILL.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
name: af-dag
|
||||||
|
description: |
|
||||||
|
Show the DAG of the current or last ArcheFlow run.
|
||||||
|
<example>User: "/af-dag"</example>
|
||||||
|
<example>User: "/af-dag 2026-04-06-jwt-auth"</example>
|
||||||
|
---
|
||||||
|
|
||||||
|
# ArcheFlow Run DAG
|
||||||
|
|
||||||
|
1. Parse `run_id` from args. If none provided, read the latest run_id from `.archeflow/events/index.jsonl`.
|
||||||
|
2. Run `./lib/archeflow-dag.sh .archeflow/events/<run_id>.jsonl` if the script exists. Display its output.
|
||||||
|
3. If the script does not exist, read `.archeflow/events/<run_id>.jsonl` and render a text DAG:
|
||||||
|
- Each node is an event (phase transitions, agent starts/completes, findings).
|
||||||
|
- Show parent relationships via indentation.
|
||||||
|
- Mark completed events with `[done]`, active with `[running]`, failed with `[FAIL]`.
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
```
|
||||||
|
run.start 2026-04-06-jwt-auth
|
||||||
|
plan.start
|
||||||
|
agent.complete explorer (42s)
|
||||||
|
agent.complete creator (68s)
|
||||||
|
do.start
|
||||||
|
agent.complete maker (180s)
|
||||||
|
check.start
|
||||||
|
agent.complete guardian (55s) -- 3 findings
|
||||||
|
agent.complete skeptic (40s) -- 1 finding
|
||||||
|
act.start
|
||||||
|
fixes.applied 3/4
|
||||||
|
run.complete (6m12s)
|
||||||
|
```
|
||||||
|
|
||||||
|
4. If no events found for the run_id, say: "No events found for run `<run_id>`."
|
||||||
40
skills/af-report/SKILL.md
Normal file
40
skills/af-report/SKILL.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
name: af-report
|
||||||
|
description: |
|
||||||
|
Generate a full process report for an ArcheFlow run.
|
||||||
|
<example>User: "/af-report"</example>
|
||||||
|
<example>User: "/af-report 2026-04-06-jwt-auth"</example>
|
||||||
|
---
|
||||||
|
|
||||||
|
# ArcheFlow Run Report
|
||||||
|
|
||||||
|
1. Parse `run_id` from args. If none provided, read the latest run_id from `.archeflow/events/index.jsonl`.
|
||||||
|
2. Run `./lib/archeflow-report.sh .archeflow/events/<run_id>.jsonl` if the script exists. Display its output.
|
||||||
|
3. If the script does not exist, read `.archeflow/events/<run_id>.jsonl` and produce a markdown report:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# ArcheFlow Report: <run_id>
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Task | ... |
|
||||||
|
| Workflow | fast/standard/thorough |
|
||||||
|
| Cycles | N |
|
||||||
|
| Duration | Xm Ys |
|
||||||
|
| Total Cost | $X.XX |
|
||||||
|
|
||||||
|
## Phase Summary
|
||||||
|
For each phase (Plan, Do, Check, Act): agents involved, duration, token cost, key outputs.
|
||||||
|
|
||||||
|
## Findings
|
||||||
|
Table of all findings: severity, category, description, archetype source, resolution (fixed/dismissed/deferred).
|
||||||
|
|
||||||
|
## Fixes Applied
|
||||||
|
List of fixes with before/after summary and which finding they addressed.
|
||||||
|
|
||||||
|
## Lessons Learned
|
||||||
|
Any new lessons extracted to memory during this run.
|
||||||
|
```
|
||||||
|
|
||||||
|
4. If no events found for the run_id, say: "No events found for run `<run_id>`."
|
||||||
23
skills/af-score/SKILL.md
Normal file
23
skills/af-score/SKILL.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
name: af-score
|
||||||
|
description: |
|
||||||
|
Show archetype effectiveness scores across runs.
|
||||||
|
<example>User: "/af-score"</example>
|
||||||
|
---
|
||||||
|
|
||||||
|
# ArcheFlow Effectiveness Scores
|
||||||
|
|
||||||
|
1. Run `./lib/archeflow-score.sh list` if the script exists. Display its output.
|
||||||
|
2. If the script does not exist, read `.archeflow/memory/effectiveness.jsonl` directly.
|
||||||
|
3. Summarize per archetype as a table:
|
||||||
|
|
||||||
|
| Archetype | Runs | Signal/Noise | Fix Rate | Avg Cost |
|
||||||
|
|-----------|------|--------------|----------|----------|
|
||||||
|
| Guardian | ... | ... | ... | ... |
|
||||||
|
| Skeptic | ... | ... | ... | ... |
|
||||||
|
|
||||||
|
- **Signal/Noise**: findings that led to actual fixes vs total findings raised.
|
||||||
|
- **Fix Rate**: percentage of findings that were applied (not dismissed).
|
||||||
|
- **Avg Cost**: mean token cost per review across runs.
|
||||||
|
|
||||||
|
4. If no effectiveness data exists, say: "No effectiveness data yet. Run `/af-run` at least once."
|
||||||
25
skills/af-status/SKILL.md
Normal file
25
skills/af-status/SKILL.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
name: af-status
|
||||||
|
description: |
|
||||||
|
Show ArcheFlow status — current/last run, active agents, findings.
|
||||||
|
<example>User: "/af-status"</example>
|
||||||
|
---
|
||||||
|
|
||||||
|
# ArcheFlow Status
|
||||||
|
|
||||||
|
1. Read `.archeflow/state.json` if it exists. Extract: task, phase, cycle, workflow, active agents, findings count, start time.
|
||||||
|
2. If `state.json` does not exist, read the latest entry from `.archeflow/events/index.jsonl`. Extract run_id, task, last event type, timestamp.
|
||||||
|
3. Calculate duration from start time to now (or to completion time if run finished).
|
||||||
|
4. Report as a compact table:
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Run | `<run_id>` |
|
||||||
|
| Task | `<task description>` |
|
||||||
|
| Phase | `<current phase>` |
|
||||||
|
| Cycle | `<cycle number>` |
|
||||||
|
| Workflow | `<fast/standard/thorough>` |
|
||||||
|
| Findings | `<count>` |
|
||||||
|
| Duration | `<elapsed>` |
|
||||||
|
|
||||||
|
5. If no `state.json` and no `index.jsonl`, say: "No active or recent ArcheFlow runs."
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
---
|
|
||||||
name: attention-filters
|
|
||||||
description: Use when spawning archetype agents to decide what context each agent receives. Reduces token waste and sharpens focus by passing only relevant artifacts.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Attention Filters
|
|
||||||
|
|
||||||
Each archetype needs different context. Pass only what's relevant — not everything.
|
|
||||||
|
|
||||||
| Archetype | Receives | Does NOT Receive |
|
|
||||||
|-----------|----------|-----------------|
|
|
||||||
| Explorer | Task description, codebase access | Prior proposals or reviews |
|
|
||||||
| Creator | Explorer's research + task description | Implementation details |
|
|
||||||
| Maker | Creator's proposal | Explorer's research, reviews |
|
|
||||||
| Guardian | Maker's git diff + proposal risk section | Explorer's research |
|
|
||||||
| Skeptic | Creator's proposal (focus: assumptions) | Git diff details |
|
|
||||||
| Trickster | Maker's git diff only | Everything else |
|
|
||||||
| Sage | Proposal + implementation + diff | Explorer's raw research |
|
|
||||||
|
|
||||||
## Why This Matters
|
|
||||||
|
|
||||||
- **Token cost:** A Guardian reading the Explorer's 2000-word research wastes ~2600 tokens on irrelevant context
|
|
||||||
- **Focus:** An agent with too much context drifts from its archetype's concern
|
|
||||||
- **Shadow prevention:** Over-loading context encourages rabbit-holing (Explorer) and scope creep (Maker)
|
|
||||||
|
|
||||||
## In Practice
|
|
||||||
|
|
||||||
When spawning a Check-phase agent, include only the filtered context in the prompt:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Guardian receives:
|
|
||||||
"Review these changes: <git diff output>
|
|
||||||
The proposal identified these risks: <risks section only>
|
|
||||||
Verdict: APPROVED or REJECTED with findings."
|
|
||||||
|
|
||||||
# NOT:
|
|
||||||
"Here is the full research, the full proposal, the full implementation,
|
|
||||||
the full git log, and everything else we have..."
|
|
||||||
```
|
|
||||||
|
|
||||||
## Prompt Construction Templates
|
|
||||||
|
|
||||||
### Explorer
|
|
||||||
- **Receives:** Task description, file tree (max 200 lines), prior-cycle feedback (if cycle 2+)
|
|
||||||
- **Excludes:** Creator proposals, Maker diffs, reviewer outputs
|
|
||||||
- **Token target:** ~2000 tokens input
|
|
||||||
|
|
||||||
### Creator
|
|
||||||
- **Receives:** Task description, Explorer research (if available), prior-cycle feedback (if cycle 2+)
|
|
||||||
- **Excludes:** Maker diffs, reviewer outputs
|
|
||||||
- **Token target:** ~3000 tokens input
|
|
||||||
|
|
||||||
### Maker
|
|
||||||
- **Receives:** Creator's proposal (full), test strategy section, file list
|
|
||||||
- **Excludes:** Explorer research, reviewer outputs, prior-cycle feedback
|
|
||||||
- **Token target:** ~2500 tokens input
|
|
||||||
|
|
||||||
### Guardian
|
|
||||||
- **Receives:** Maker's git diff, proposal risk section, test results
|
|
||||||
- **Excludes:** Explorer research, Creator rationale, Skeptic/Sage outputs
|
|
||||||
- **Token target:** ~2000 tokens input
|
|
||||||
|
|
||||||
### Skeptic
|
|
||||||
- **Receives:** Creator's proposal (assumptions + architecture decision), confidence scores
|
|
||||||
- **Excludes:** Git diff details, Explorer raw research, other reviewer outputs
|
|
||||||
- **Token target:** ~1500 tokens input
|
|
||||||
|
|
||||||
### Trickster
|
|
||||||
- **Receives:** Maker's git diff only, attack surface summary (file types + entry points)
|
|
||||||
- **Excludes:** Proposal, research, other reviewer outputs
|
|
||||||
- **Token target:** ~1500 tokens input
|
|
||||||
|
|
||||||
### Sage
|
|
||||||
- **Receives:** Creator's proposal, Maker's implementation summary + diff, test results
|
|
||||||
- **Excludes:** Explorer raw research, other reviewer verdicts
|
|
||||||
- **Token target:** ~2500 tokens input
|
|
||||||
|
|
||||||
## Token Budget Targets
|
|
||||||
|
|
||||||
| Archetype | Fast | Standard | Thorough |
|
|
||||||
|-----------|------|----------|----------|
|
|
||||||
| Explorer | skip | 2000 | 3000 |
|
|
||||||
| Creator | 2000 | 3000 | 4000 |
|
|
||||||
| Maker | 2000 | 2500 | 3000 |
|
|
||||||
| Guardian | 1500 | 2000 | 2500 |
|
|
||||||
| Skeptic | skip | 1500 | 2000 |
|
|
||||||
| Trickster | skip | skip | 1500 |
|
|
||||||
| Sage | skip | 2500 | 3000 |
|
|
||||||
|
|
||||||
"skip" means the archetype is not spawned in that workflow tier.
|
|
||||||
|
|
||||||
## Cycle-Back Filtering
|
|
||||||
|
|
||||||
When injecting prior-cycle feedback into cycle 2+:
|
|
||||||
|
|
||||||
1. **Summary only** — pass the structured feedback table (issue, source, severity), not full reviewer artifacts
|
|
||||||
2. **Strip resolved items** — if a finding was marked Fixed in the Act phase, exclude it
|
|
||||||
3. **Compress context** — prior proposal diffs reduce to "What Changed" section only (not full re-proposal)
|
|
||||||
4. **Cap at 500 tokens** — if feedback exceeds this, summarize by severity (CRITICAL first, then WARNING, drop INFO)
|
|
||||||
|
|
||||||
## Filter Verification Checklist
|
|
||||||
|
|
||||||
Before spawning each agent, verify:
|
|
||||||
|
|
||||||
- [ ] Prompt contains ONLY the artifacts listed in that archetype's "Receives" above
|
|
||||||
- [ ] No cross-contamination from other reviewers' outputs
|
|
||||||
- [ ] Token count is within 20% of the target for the current workflow tier
|
|
||||||
- [ ] Prior-cycle feedback (if any) is summarized, not raw
|
|
||||||
- [ ] Excluded artifacts are genuinely absent (search for keywords like file paths from excluded sources)
|
|
||||||
|
|
||||||
## Context Isolation
|
|
||||||
|
|
||||||
Attention filters control *what* each agent receives. Context isolation controls *how* that context is constructed — ensuring agents operate on provided facts, not ambient knowledge.
|
|
||||||
|
|
||||||
### Rules
|
|
||||||
|
|
||||||
1. **No session bleed.** Agents receive fresh context only — constructed from task description, artifact files, or extracted sections. They must not inherit session state, chat history, or prior agent prompts.
|
|
||||||
2. **No cross-agent contamination.** An agent receives another agent's output only if the attention filter table above explicitly allows it. Guardian does not see Skeptic's output. Skeptic does not see the Maker's diff. Violations produce unreliable reviews.
|
|
||||||
3. **Controller-constructed only.** All agent context is assembled by the orchestrator from: (a) the task description, (b) artifact files on disk, or (c) extracted sections of those artifacts. Agents never pull their own context.
|
|
||||||
4. **No ambient knowledge.** Agents cannot "remember" findings from prior phases or cycles unless that information is explicitly injected via the cycle-back filtering protocol above. An agent that references information not in its prompt is hallucinating.
|
|
||||||
5. **Verification.** Before spawning each agent, confirm the constructed prompt has zero references to other agents' raw outputs that are not in the "Receives" column. Search for file paths, archetype names, and finding descriptions from excluded sources.
|
|
||||||
@@ -1,233 +1,110 @@
|
|||||||
---
|
---
|
||||||
name: check-phase
|
name: check-phase
|
||||||
description: Use when you are acting as Guardian, Skeptic, Sage, or Trickster archetype in the Check phase. Defines shared review rules and output format.
|
description: Use when acting as Guardian, Skeptic, Sage, or Trickster in the Check phase. Defines review rules, finding format, attention filters, and spawning protocol.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Check Phase
|
# Check Phase
|
||||||
|
|
||||||
Multiple reviewers examine the Maker's implementation in parallel. Each agent definition has its specific protocol — this skill defines the shared rules.
|
Reviewers examine the Maker's implementation. This skill defines shared rules, finding format, and spawning protocol.
|
||||||
|
|
||||||
## Shared Rules
|
## Shared Rules
|
||||||
|
|
||||||
1. **Read the proposal first.** Review against the intended design, not invented requirements.
|
1. Review against the proposal's intended design, not invented requirements.
|
||||||
2. **Read the actual code.** Use `git diff` on the Maker's branch. Don't review descriptions alone.
|
2. Read actual code via `git diff` on the Maker's branch.
|
||||||
3. **Structured findings.** Use the standardized finding format below for every issue.
|
3. Use the finding format below for every issue.
|
||||||
4. **Clear verdict:** `APPROVED` or `REJECTED` with rationale.
|
4. Give a clear verdict: `APPROVED` or `REJECTED` with rationale.
|
||||||
5. **Status tokens are separate from verdicts.** The `STATUS: DONE` line signals the agent finished successfully. The `APPROVED`/`REJECTED` verdict is domain output. A reviewer can be `STATUS: DONE` with verdict `REJECTED` — that is normal. Parse both independently.
|
5. `STATUS: DONE` signals agent completion. `APPROVED`/`REJECTED` is domain output. Both are parsed independently.
|
||||||
|
|
||||||
## Finding Format
|
## Finding Format
|
||||||
|
|
||||||
Every finding must use this format for cross-cycle tracking:
|
|
||||||
|
|
||||||
```
|
|
||||||
| Location | Severity | Category | Description | Fix |
|
| Location | Severity | Category | Description | Fix |
|
||||||
|----------|----------|----------|-------------|-----|
|
|----------|----------|----------|-------------|-----|
|
||||||
| src/auth/handler.ts:48 | CRITICAL | security | Empty string bypasses validation | Add length check before processing |
|
| src/auth/handler.ts:48 | CRITICAL | security | Empty string bypasses validation | Add length check |
|
||||||
```
|
|
||||||
|
|
||||||
**Severity:**
|
**Severity:** CRITICAL = must fix, blocks approval. WARNING = should fix, doesn't block alone. INFO = nice to have, never blocks.
|
||||||
- **CRITICAL** — Must fix. Blocks approval.
|
|
||||||
- **WARNING** — Should fix. Doesn't block alone.
|
|
||||||
- **INFO** — Nice to have. Never blocks.
|
|
||||||
|
|
||||||
**Categories** (use consistently for cross-cycle tracking):
|
**Categories:** `security` `reliability` `design` `breaking-change` `dependency` `quality` `testing` `consistency`
|
||||||
- `security` — Injection, auth bypass, data exposure, secrets
|
|
||||||
- `reliability` — Error handling, edge cases, race conditions, crashes
|
|
||||||
- `design` — Architecture, assumptions, scalability, coupling
|
|
||||||
- `breaking-change` — API compatibility, schema migrations, removals
|
|
||||||
- `dependency` — New deps, version conflicts, license issues
|
|
||||||
- `quality` — Readability, maintainability, naming, duplication
|
|
||||||
- `testing` — Missing tests, weak assertions, untested paths
|
|
||||||
- `consistency` — Deviates from codebase patterns
|
|
||||||
|
|
||||||
## Consolidated Output
|
## Evidence Requirements
|
||||||
|
|
||||||
After all reviewers finish, compile:
|
Every CRITICAL or WARNING must include concrete evidence. Without evidence, downgrade to INFO.
|
||||||
|
|
||||||
```markdown
|
**Valid evidence:** command output, exit codes, code citations with line numbers, git diff excerpts, reproduction steps.
|
||||||
## Check Phase Results — Cycle N
|
|
||||||
|
|
||||||
### Guardian: APPROVED
|
**Banned in CRITICAL/WARNING:** "might be", "could potentially", "appears to", "seems like", "may not". Rewrite with evidence or downgrade.
|
||||||
| Location | Severity | Category | Description | Fix |
|
|
||||||
|----------|----------|----------|-------------|-----|
|
|
||||||
| src/auth/handler.ts:52 | WARNING | security | Missing rate limit | Add rate limiter middleware |
|
|
||||||
|
|
||||||
### Skeptic: APPROVED
|
For each CRITICAL/WARNING, state: (1) what was tested, (2) what was observed, (3) what correct behavior should be.
|
||||||
| Location | Severity | Category | Description | Fix |
|
|
||||||
|----------|----------|----------|-------------|-----|
|
|
||||||
| src/auth/handler.ts:30 | INFO | design | Consider caching validated tokens | Add TTL cache for token validation |
|
|
||||||
|
|
||||||
### Sage: APPROVED
|
## Attention Filters
|
||||||
| Location | Severity | Category | Description | Fix |
|
|
||||||
|----------|----------|----------|-------------|-----|
|
|
||||||
| tests/auth.test.ts:15 | WARNING | testing | Test names don't describe behavior | Rename to "should reject expired tokens" |
|
|
||||||
|
|
||||||
### Trickster: REJECTED
|
Each archetype receives only relevant context. Do not pass everything.
|
||||||
| Location | Severity | Category | Description | Fix |
|
|
||||||
|----------|----------|----------|-------------|-----|
|
|
||||||
| src/auth/handler.ts:48 | CRITICAL | reliability | Empty string bypasses validation | Add `if (!token || token.trim() === '')` guard |
|
|
||||||
|
|
||||||
### Deduplication
|
| Archetype | Receives | Excludes |
|
||||||
If two reviewers raise the same issue (same file + same category), merge:
|
|-----------|----------|----------|
|
||||||
| Guardian + Skeptic | CRITICAL | security | Input not sanitized (src/api.ts:30) | Add validation |
|
| Guardian | Maker's git diff + proposal risk section + test results | Explorer research, Creator rationale, other reviewers |
|
||||||
|
| Skeptic | Creator's proposal (assumptions + architecture) + confidence scores | Git diff, Explorer research, other reviewers |
|
||||||
|
| Sage | Creator's proposal + Maker's diff + implementation summary + test results | Explorer raw research, other reviewer verdicts |
|
||||||
|
| Trickster | Maker's git diff + attack surface summary (file types + entry points) | Proposal, research, other reviewers |
|
||||||
|
|
||||||
Use the higher severity. Don't double-count in the verdict.
|
**Token budget targets:**
|
||||||
|
|
||||||
### Verdict: REJECTED — 1 critical finding
|
| Archetype | Fast | Standard | Thorough |
|
||||||
→ Build cycle feedback (see orchestration skill) and feed to Plan phase
|
|-----------|------|----------|----------|
|
||||||
```
|
| Guardian | 1500 | 2000 | 2500 |
|
||||||
|
| Skeptic | skip | 1500 | 2000 |
|
||||||
|
| Trickster | skip | skip | 1500 |
|
||||||
|
| Sage | skip | 2500 | 3000 |
|
||||||
|
|
||||||
|
**Context isolation:** Agents receive fresh, controller-constructed context only. No session bleed, no cross-agent contamination, no ambient knowledge. Verify zero references to excluded artifacts before spawning.
|
||||||
|
|
||||||
|
**Cycle-back filtering (cycle 2+):** Pass structured feedback table only (not full reviewer artifacts). Strip resolved items. Cap at 500 tokens — summarize by severity if exceeded.
|
||||||
|
|
||||||
## Reviewer Spawning Protocol
|
## Reviewer Spawning Protocol
|
||||||
|
|
||||||
This section defines the exact sequence for spawning reviewers in the Check phase.
|
|
||||||
|
|
||||||
### Step 1: Guardian First (mandatory)
|
### Step 1: Guardian First (mandatory)
|
||||||
|
|
||||||
Guardian always runs first, before any other reviewer. It receives the Maker's git diff and the proposal's risk section only.
|
Guardian always runs first. It receives the Maker's git diff and the proposal's risk section only.
|
||||||
|
|
||||||
**Context for Guardian:**
|
|
||||||
- `git diff main...<maker-branch>` (the actual code changes)
|
|
||||||
- Risk section from `plan-creator.md` (if present)
|
|
||||||
- Do NOT include: Explorer research, full proposal, other reviewer outputs
|
|
||||||
|
|
||||||
```
|
|
||||||
Agent(
|
|
||||||
description: "Guardian: security and risk review for <task>",
|
|
||||||
prompt: "You are the GUARDIAN archetype.
|
|
||||||
Review the diff: <maker's diff>
|
|
||||||
Proposal risks: <risk section from plan-creator.md>
|
|
||||||
Assess: security vulnerabilities, reliability risks, breaking changes, dependency risks.
|
|
||||||
Output: APPROVED or REJECTED with findings in the standardized format.
|
|
||||||
Each finding: | Location | Severity | Category | Description | Fix |",
|
|
||||||
model: <resolve_model guardian $WORKFLOW>
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Save output to `.archeflow/artifacts/${RUN_ID}/check-guardian.md`.
|
Save output to `.archeflow/artifacts/${RUN_ID}/check-guardian.md`.
|
||||||
|
|
||||||
### Step 2: A2 Fast-Path Evaluation
|
### Step 2: A2 Fast-Path Evaluation
|
||||||
|
|
||||||
After Guardian completes, parse its output before spawning other reviewers:
|
After Guardian completes, count CRITICAL and WARNING findings in its output. If both are zero, and not escalated, and not first cycle of a thorough workflow — skip remaining reviewers and proceed to Act phase.
|
||||||
|
|
||||||
```bash
|
### Step 3: Parallel Remaining Reviewers
|
||||||
CRITICAL_COUNT=$(grep -c "| CRITICAL |" ".archeflow/artifacts/${RUN_ID}/check-guardian.md" || echo 0)
|
|
||||||
WARNING_COUNT=$(grep -c "| WARNING |" ".archeflow/artifacts/${RUN_ID}/check-guardian.md" || echo 0)
|
|
||||||
|
|
||||||
# A2 fast-path: skip remaining reviewers if Guardian is clean
|
If A2 does not trigger, spawn remaining reviewers in parallel:
|
||||||
# Exception: first cycle of thorough workflows always spawns all reviewers
|
|
||||||
if [[ "$CRITICAL_COUNT" -eq 0 && "$WARNING_COUNT" -eq 0 \
|
|
||||||
&& "$ESCALATED" != "true" \
|
|
||||||
&& ! ("$WORKFLOW" == "thorough" && "$CYCLE" -eq 1) ]]; then
|
|
||||||
echo "Guardian fast-path: 0 CRITICAL, 0 WARNING — skipping remaining reviewers."
|
|
||||||
# Proceed directly to Act phase
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Parallel Reviewer Spawning
|
|
||||||
|
|
||||||
If A2 does not trigger, spawn remaining reviewers in parallel based on workflow:
|
|
||||||
|
|
||||||
| Workflow | Reviewers (after Guardian) |
|
| Workflow | Reviewers (after Guardian) |
|
||||||
|----------|--------------------------|
|
|----------|--------------------------|
|
||||||
| `fast` | None (Guardian only) |
|
| `fast` | None (Guardian only) |
|
||||||
| `fast` (escalated via A1) | Skeptic + Sage |
|
| `fast` (escalated) | Skeptic + Sage |
|
||||||
| `standard` | Skeptic + Sage |
|
| `standard` | Skeptic + Sage |
|
||||||
| `thorough` | Skeptic + Sage + Trickster |
|
| `thorough` | Skeptic + Sage + Trickster |
|
||||||
|
|
||||||
Spawn all applicable reviewers in a single message with multiple Agent calls:
|
Each reviewer gets context per the attention filters above.
|
||||||
|
|
||||||
```
|
### Step 4: Collect and Consolidate
|
||||||
# Standard workflow example — spawn Skeptic and Sage in parallel:
|
|
||||||
Agent(
|
|
||||||
description: "Skeptic: challenge assumptions for <task>",
|
|
||||||
prompt: "<Skeptic prompt with Creator's proposal>",
|
|
||||||
model: <resolve_model skeptic $WORKFLOW>
|
|
||||||
)
|
|
||||||
|
|
||||||
Agent(
|
For each reviewer: save to `.archeflow/artifacts/${RUN_ID}/check-<archetype>.md`, emit `review.verdict` event, record sequence number.
|
||||||
description: "Sage: holistic quality review for <task>",
|
|
||||||
prompt: "<Sage prompt with proposal + diff + implementation summary>",
|
**Deduplication:** If two reviewers raise the same issue (same file + same category), merge into one finding using the higher severity. Don't double-count.
|
||||||
model: <resolve_model sage $WORKFLOW>
|
|
||||||
)
|
**Verdict:** Count CRITICAL findings across all reviewers (after dedup). Any CRITICAL = `REJECTED`. Otherwise `APPROVED`.
|
||||||
|
|
||||||
|
Example consolidated output:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Check Phase Results — Cycle 1
|
||||||
|
### Guardian: APPROVED
|
||||||
|
| Location | Severity | Category | Description | Fix |
|
||||||
|
|----------|----------|----------|-------------|-----|
|
||||||
|
| src/auth.ts:52 | WARNING | security | Missing rate limit | Add rate limiter |
|
||||||
|
### Verdict: APPROVED — 0 critical, 1 warning
|
||||||
```
|
```
|
||||||
|
|
||||||
Each reviewer gets context per the attention filters defined in `archeflow:orchestration`:
|
## Timeout Handling
|
||||||
- **Skeptic:** Creator's proposal (assumptions section focus)
|
|
||||||
- **Sage:** Creator's proposal + Maker's diff + implementation summary
|
|
||||||
- **Trickster:** Maker's diff only
|
|
||||||
|
|
||||||
### Step 4: Collect Results
|
Each reviewer has a **5-minute timeout**. On timeout: emit `agent.complete` with `"error": true`, log WARNING, treat as no findings, proceed.
|
||||||
|
|
||||||
Wait for all spawned reviewers to return. For each:
|
**Exception:** Guardian timeout is blocking — abort Check phase and report to user.
|
||||||
1. Save output to `.archeflow/artifacts/${RUN_ID}/check-<archetype>.md`
|
|
||||||
2. Emit `review.verdict` event with findings
|
|
||||||
3. Record sequence number for DAG parent tracking
|
|
||||||
|
|
||||||
### Timeout Handling
|
|
||||||
|
|
||||||
Each reviewer has a **5-minute timeout**. If a reviewer does not return within 5 minutes:
|
|
||||||
1. Emit `agent.complete` with `"error": true, "reason": "timeout"`
|
|
||||||
2. Log a WARNING — do not block the run
|
|
||||||
3. Treat the timed-out reviewer as having delivered no findings (neither approved nor rejected)
|
|
||||||
4. Proceed with available verdicts
|
|
||||||
|
|
||||||
If Guardian times out, this is a blocking failure — abort the Check phase and report to the user.
|
|
||||||
|
|
||||||
### Re-Check Protocol (Act Phase Fixes)
|
|
||||||
|
|
||||||
When the Act phase routes findings back to the Maker and the Maker applies fixes in a subsequent cycle, the Check phase re-runs with the updated diff. Reviewers who previously rejected should focus on whether their specific findings were addressed. The structured feedback from `act-feedback.md` provides the mapping of which findings were routed where.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Evidence Requirements
|
|
||||||
|
|
||||||
Every CRITICAL or WARNING finding must include concrete evidence. Findings without evidence are downgraded to INFO.
|
|
||||||
|
|
||||||
### Evidence Types
|
|
||||||
|
|
||||||
| Type | Example | When Required |
|
|
||||||
|------|---------|---------------|
|
|
||||||
| Command output | `npm test` output showing failure | Test-related findings |
|
|
||||||
| Exit code | `exit code 1 from eslint` | Tool-based validation |
|
|
||||||
| Code citation | `src/auth.ts:48 — \`if (token) { ... }\`` | Logic or security findings |
|
|
||||||
| Git diff | `+ db.query(userInput)` (unsanitized) | Implementation review |
|
|
||||||
| Reproduction steps | "1. Send POST with empty body, 2. Observe 500" | Runtime behavior findings |
|
|
||||||
|
|
||||||
### Banned Phrases
|
|
||||||
|
|
||||||
The following phrases are not permitted in CRITICAL or WARNING findings. They indicate speculation, not evidence:
|
|
||||||
|
|
||||||
- "might be"
|
|
||||||
- "could potentially"
|
|
||||||
- "appears to"
|
|
||||||
- "seems like"
|
|
||||||
- "may not"
|
|
||||||
|
|
||||||
A finding using these phrases must either be rewritten with evidence or downgraded to INFO.
|
|
||||||
|
|
||||||
### Verification Protocol
|
|
||||||
|
|
||||||
For each CRITICAL or WARNING finding, state:
|
|
||||||
|
|
||||||
1. **What was tested** — the specific code path, input, or scenario examined
|
|
||||||
2. **What was observed** — the actual behavior or code construct found
|
|
||||||
3. **What correct behavior should be** — the expected alternative
|
|
||||||
|
|
||||||
### Downgrade Rule
|
|
||||||
|
|
||||||
If a reviewer produces a CRITICAL or WARNING finding without any of the evidence types above, the orchestrator downgrades it to INFO and emits a `decision` event:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./lib/archeflow-event.sh "$RUN_ID" decision check "" \
|
|
||||||
'{"what":"evidence_downgrade","from":"CRITICAL","to":"INFO","finding":"<description>","reviewer":"<archetype>","reason":"no evidence provided"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Why Structured Findings Matter
|
|
||||||
|
|
||||||
The standardized format enables:
|
|
||||||
- **Cross-cycle tracking:** Same category + location = same issue. Can detect resolution or regression.
|
|
||||||
- **Feedback routing:** Security/design findings → Creator. Quality/testing findings → Maker.
|
|
||||||
- **Shadow detection:** CRITICAL:WARNING ratios, finding counts, and category distributions are measurable.
|
|
||||||
- **Metrics:** Severity counts feed into the orchestration summary.
|
|
||||||
|
|||||||
@@ -1,66 +1,129 @@
|
|||||||
---
|
---
|
||||||
name: shadow-detection
|
name: shadow-detection
|
||||||
description: Use when monitoring agent behavior for dysfunction, when an agent seems stuck, or when orchestration quality is degrading. Detects and corrects Jungian shadow activation in archetypes.
|
description: |
|
||||||
|
Corrective action framework for agent dysfunction, system health, and operational policy.
|
||||||
|
Three layers — archetype shadows, system shadows, policy boundaries — one escalation protocol.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Shadow Detection
|
# Corrective Action Framework
|
||||||
|
|
||||||
Every archetype has a virtue and a shadow (its destructive inversion). Shadow activates when the virtue is pushed too far.
|
Detect dysfunction. Apply corrective action. Escalate if repeated.
|
||||||
|
|
||||||
| Archetype | Virtue | Shadow |
|
Three layers, one protocol:
|
||||||
|-----------|--------|--------|
|
- **Archetype Shadows** — individual agent dysfunction (virtue pushed too far)
|
||||||
| Explorer | Contextual Clarity | Rabbit Hole |
|
- **System Shadows** — orchestration-level dysfunction (process going wrong)
|
||||||
| Creator | Decisive Framing | Over-Architect |
|
- **Policy Boundaries** — operational limits (time, cost, quality thresholds)
|
||||||
| Maker | Execution Discipline | Rogue |
|
|
||||||
| Guardian | Threat Intuition | Paranoid |
|
|
||||||
| Skeptic | Assumption Surfacing | Paralytic |
|
|
||||||
| Trickster | Adversarial Creativity | False Alarm |
|
|
||||||
| Sage | Maintainability Judgment | Bureaucrat |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Explorer -> Rabbit Hole
|
## Archetype Shadows
|
||||||
**Detect** (any): output >2000w without Recommendation | >3 tangents | >15 files no patterns | no synthesis in final 25%
|
|
||||||
**Correct**: "Summarize top 3 findings and one recommendation in under 300 words."
|
|
||||||
|
|
||||||
### Creator -> Over-Architect
|
| Archetype | Shadow | Detect (any) | Corrective Action |
|
||||||
**Detect** (any): >2 new abstractions for a single feature | "future-proof" in rationale | scope exceeds task by >50% | >1 new package for one feature
|
|-----------|--------|-------------|-------------------|
|
||||||
**Correct**: "Design for the current order of magnitude. Remove abstractions that serve hypothetical requirements."
|
| Explorer | Rabbit Hole | Output >2000w without Recommendation; >3 tangents; >15 files no patterns; no synthesis in final 25% | "Summarize top 3 findings and one recommendation in 300 words." |
|
||||||
|
| Creator | Over-Architect | >2 new abstractions for one feature; "future-proof" in rationale; scope exceeds task >50%; >1 new package | "Design for the current order of magnitude. Remove abstractions for hypothetical requirements." |
|
||||||
|
| Maker | Rogue | Zero test files with >=3 files changed; single monolithic commit; files outside proposal; no test run evidence | "Read the proposal. Write a test. Commit. Revert out-of-scope files." |
|
||||||
|
| Guardian | Paranoid | CRITICAL:WARNING ratio >2:1 (min 3); zero APPROVED in 3+ reviews; <50% findings include fix; findings require compromised systems | "For each CRITICAL: would a senior engineer block a PR? If not, downgrade. Every rejection needs a specific fix." |
|
||||||
|
| Skeptic | Paralytic | >7 challenges; <50% include alternatives; same concern 2+ times reworded; >3 findings outside scope | "Rank by impact. Keep top 3 with alternatives. Delete the rest." |
|
||||||
|
| Trickster | False Alarm | Findings in untouched code; >10 findings for <5 files; impossible scenarios; >3 without repro steps | "Delete findings outside the diff. Rank by likelihood x impact. Keep top 3-5." |
|
||||||
|
| Sage | Bureaucrat | Review words >2x diff lines; findings outside changeset; >2 "consider" without action; suggesting docs for trivial functions | "Limit to issues affecting maintainability in 6 months. Every finding needs a specific action." |
|
||||||
|
|
||||||
### Maker -> Rogue
|
### Shadow Immunity
|
||||||
**Detect** (any): zero test files with >=3 files changed | single monolithic commit | diff contains files not in proposal | no evidence of running tests
|
|
||||||
**Correct**: "Read the proposal. Write a test. Commit what you have. Revert changes to files not in the proposal."
|
|
||||||
|
|
||||||
### Guardian -> Paranoid
|
Intensity alone is not a shadow. **Shadow = behavior disconnected from the goal.**
|
||||||
**Detect** (any): CRITICAL:WARNING ratio >2:1 (min 3 findings) | zero APPROVED in 3+ reviews | <50% findings include a fix | findings require already-compromised systems
|
|
||||||
**Correct**: "For each CRITICAL: would a senior engineer block a PR for this? If not, downgrade. Every rejection must include a specific fix."
|
|
||||||
|
|
||||||
### Skeptic -> Paralytic
|
- Explorer reading 20 files in a monorepo with scattered deps -- not rabbit hole if each is relevant
|
||||||
**Detect** (any): >7 challenges in a single review | <50% include alternatives | same concern appears 2+ times reworded | >3 findings outside task scope
|
- Guardian blocking with 2 CRITICALs -- not paranoid if both are genuine vulnerabilities
|
||||||
**Correct**: "Rank challenges by impact. Keep top 3. Each must include a specific alternative. Delete the rest."
|
|
||||||
|
|
||||||
### Trickster -> False Alarm
|
|
||||||
**Detect** (any): findings reference code untouched by diff | >10 findings for <5 files | impossible deployment scenarios | >3 findings without repro steps
|
|
||||||
**Correct**: "Delete findings outside the diff. Rank remaining by likelihood x impact. Keep top 3-5."
|
|
||||||
|
|
||||||
### Sage -> Bureaucrat
|
|
||||||
**Detect** (any): review words >2x diff lines | findings reference files not in changeset | >2 "consider" without concrete action | suggesting docs for <5-line functions
|
|
||||||
**Correct**: "Limit to issues affecting maintainability in the next 6 months. Every finding must end with a specific action."
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Escalation Protocol
|
|
||||||
|
|
||||||
1. **1st detection:** Log the shadow, apply the correction prompt, let the agent continue
|
|
||||||
2. **2nd detection (same agent, same shadow):** Replace the agent -- the shadow is entrenched
|
|
||||||
3. **3+ agents shadowed in same cycle:** Escalate to user -- the task may need to be broken down
|
|
||||||
|
|
||||||
## Shadow Immunity
|
|
||||||
|
|
||||||
Some behaviors look like shadows but are not. **Rule of thumb:** shadow = behavior disconnected from the goal. Intensity alone is not a shadow.
|
|
||||||
|
|
||||||
- Explorer reading 20 files in a monorepo with scattered dependencies -- not a rabbit hole if each file is genuinely relevant
|
|
||||||
- Creator adding an abstraction -- not over-architect if the current task genuinely needs it
|
|
||||||
- Guardian blocking with 2 CRITICALs -- not paranoid if both are genuine security vulnerabilities
|
|
||||||
- Trickster finding 5 edge cases -- not false alarm if all are in changed code with repro steps
|
- Trickster finding 5 edge cases -- not false alarm if all are in changed code with repro steps
|
||||||
- Sage writing a long review -- not bureaucrat if the change is large and every finding is actionable
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## System Shadows
|
||||||
|
|
||||||
|
Orchestration-level dysfunction that isn't tied to one archetype.
|
||||||
|
|
||||||
|
| Shadow | Detect | Corrective Action |
|
||||||
|
|--------|--------|-------------------|
|
||||||
|
| **Tunnel Vision** | All reviewers flag same category (e.g., 4 security findings, 0 quality/testing) | "Redistribute attention. Are we missing quality, testing, or design concerns?" |
|
||||||
|
| **Echo Chamber** | Unanimous approval in <30s on standard/thorough workflow | "Suspicious fast consensus. Re-run Guardian with adversarial prompt." |
|
||||||
|
| **Gold Plating** | Maker working on INFO fixes while CRITICALs remain open | "Fix CRITICALs first. Park INFO items." |
|
||||||
|
| **Analysis Paralysis** | Plan phase >2x longer than Do phase; Explorer spawned 3+ times | "Stop researching. Ship a proposal with known gaps." |
|
||||||
|
| **Cargo Cult** | Memory lesson injected but the same finding repeats anyway | "Lesson ineffective. Reword, strengthen, or remove it." |
|
||||||
|
| **Broken Window** | 3+ WARNINGs deferred across consecutive runs in the same project | "Accumulated tech debt. Schedule a cleanup sprint." |
|
||||||
|
| **Scope Creep** | Maker changes >2x files listed in proposal | "Revert to proposal scope. If more files needed, update the proposal first." |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Policy Boundaries
|
||||||
|
|
||||||
|
Operational limits that protect session quality, cost, and resumability.
|
||||||
|
|
||||||
|
### Checkpoint Policy
|
||||||
|
|
||||||
|
Every **45 minutes** or **3 completed tasks** (whichever first):
|
||||||
|
|
||||||
|
1. Commit + push all work in progress
|
||||||
|
2. Write handoff summary to `control-center.md`
|
||||||
|
3. Log token spend so far
|
||||||
|
4. Compare output quality: last task vs first task
|
||||||
|
5. If quality degrading -> STOP with clean state
|
||||||
|
6. If budget >80% spent -> STOP with clean state
|
||||||
|
7. Otherwise -> continue
|
||||||
|
|
||||||
|
### Budget Gate
|
||||||
|
|
||||||
|
| Threshold | Action |
|
||||||
|
|-----------|--------|
|
||||||
|
| 50% budget spent | Log warning, continue |
|
||||||
|
| 80% budget spent | Downgrade models (sonnet->haiku for reviewers) |
|
||||||
|
| 95% budget spent | Complete current task, then STOP |
|
||||||
|
| 100% budget | STOP immediately, commit WIP |
|
||||||
|
|
||||||
|
### Circuit Breaker
|
||||||
|
|
||||||
|
| Trigger | Action |
|
||||||
|
|---------|--------|
|
||||||
|
| 3 consecutive agent failures/timeouts | STOP. Infrastructure issue, not a code problem. |
|
||||||
|
| 3 consecutive task failures in sprint | STOP. Something systemic is wrong. |
|
||||||
|
| Same shadow detected 3+ times in one cycle | STOP. Task needs to be broken down or re-scoped. |
|
||||||
|
| Test suite broken after merge | Auto-revert, STOP, report. |
|
||||||
|
|
||||||
|
### Diminishing Returns
|
||||||
|
|
||||||
|
| Signal | Action |
|
||||||
|
|--------|--------|
|
||||||
|
| Cycle N findings identical to cycle N-1 | STOP cycling. Present best result. |
|
||||||
|
| Convergence score <0.5 for 2 consecutive cycles | STOP. "This needs a different approach." |
|
||||||
|
| Reviewer finding count increases cycle over cycle | STOP. Implementation is diverging, not converging. |
|
||||||
|
|
||||||
|
### Context Pollution
|
||||||
|
|
||||||
|
| Signal | Action |
|
||||||
|
|--------|--------|
|
||||||
|
| >15 memory lessons injected into one prompt | Prune to top 5 by frequency |
|
||||||
|
| >20 findings tracked across cycles | Summarize into top 5 themes |
|
||||||
|
| Agent prompt exceeds estimated 50% of context window | Strip examples, keep rules only |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Unified Escalation Protocol
|
||||||
|
|
||||||
|
All three layers use the same escalation:
|
||||||
|
|
||||||
|
| Step | Archetype Shadows | System Shadows | Policy Boundaries |
|
||||||
|
|------|-------------------|----------------|-------------------|
|
||||||
|
| **1st** | Apply corrective action, let agent continue | Apply corrective action, continue run | Apply boundary action (downgrade, checkpoint) |
|
||||||
|
| **2nd** (same issue) | Replace the agent -- shadow is entrenched | Pause run, report to user | Force stop with clean state |
|
||||||
|
| **3rd** (pattern) | Escalate to user: "task needs re-scoping" | Escalate to user: "systemic issue" | Escalate to user: "resource limits reached" |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Integration
|
||||||
|
|
||||||
|
Shadow checks run **after each agent completes** during orchestration. System shadow checks run **at phase boundaries**. Policy checks run **on a timer and at task boundaries**.
|
||||||
|
|
||||||
|
The `run` skill references this framework at:
|
||||||
|
- Step 3 (Check phase): archetype shadow monitoring
|
||||||
|
- Step 4 (Act phase): convergence/diminishing returns
|
||||||
|
- Step 5 (Completion): effectiveness scoring
|
||||||
|
- Sprint skill: checkpoint policy between batches
|
||||||
|
|||||||
22
skills/using-archeflow/ACTIVATION.md
Normal file
22
skills/using-archeflow/ACTIVATION.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# ArcheFlow -- Active
|
||||||
|
|
||||||
|
Multi-agent orchestration using archetypal roles and PDCA quality cycles.
|
||||||
|
|
||||||
|
## Session Start
|
||||||
|
|
||||||
|
On activation, print ONE line then proceed silently:
|
||||||
|
```
|
||||||
|
archeflow v0.8.0 · 19 skills · <domain> domain
|
||||||
|
```
|
||||||
|
Domain: `writing` if `colette.yaml` exists, `research` if paper/thesis files, `code` otherwise.
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
| Need | Command |
|
||||||
|
|------|---------|
|
||||||
|
| Work the queue | `/af-sprint` |
|
||||||
|
| Deep orchestration | `/af-run <task>` |
|
||||||
|
| Code review | `/af-review` |
|
||||||
|
| Simple fix / question | Skip ArcheFlow — just do it directly |
|
||||||
|
|
||||||
|
Do NOT use ArcheFlow for: single-line fixes, questions, reading code, config tweaks, git ops.
|
||||||
@@ -7,7 +7,7 @@ description: Use at session start when implementing features, reviewing code, de
|
|||||||
|
|
||||||
On activation, print ONE line then proceed silently:
|
On activation, print ONE line then proceed silently:
|
||||||
```
|
```
|
||||||
archeflow v0.7.0 · 25 skills · <domain> domain
|
archeflow v0.8.0 · 23 skills · <domain> domain
|
||||||
```
|
```
|
||||||
Domain auto-detected: `writing` if `colette.yaml` exists, `research` if paper/thesis files, `code` otherwise.
|
Domain auto-detected: `writing` if `colette.yaml` exists, `research` if paper/thesis files, `code` otherwise.
|
||||||
|
|
||||||
|
|||||||
71
tests/archeflow-dag.bats
Normal file
71
tests/archeflow-dag.bats
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# Tests for archeflow-dag.sh — ASCII DAG rendering from JSONL events.
|
||||||
|
#
|
||||||
|
# Validates: basic rendering, parent relationships, color flags, missing file handling.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
|
||||||
|
# Create a standard events file with parent relationships
|
||||||
|
cat > "$BATS_TEST_TMPDIR/dag-events.jsonl" <<'EVENTS'
|
||||||
|
{"ts":"2026-04-03T10:00:00Z","run_id":"dag-run","seq":1,"parent":[],"type":"run.start","phase":"plan","agent":null,"data":{"task":"DAG test"}}
|
||||||
|
{"ts":"2026-04-03T10:01:00Z","run_id":"dag-run","seq":2,"parent":[1],"type":"agent.complete","phase":"plan","agent":"creator","data":{"archetype":"creator","duration_ms":60000,"tokens":1500}}
|
||||||
|
{"ts":"2026-04-03T10:02:00Z","run_id":"dag-run","seq":3,"parent":[2],"type":"phase.transition","phase":"do","agent":null,"data":{"from":"plan","to":"do"}}
|
||||||
|
{"ts":"2026-04-03T10:03:00Z","run_id":"dag-run","seq":4,"parent":[3],"type":"agent.complete","phase":"do","agent":"maker","data":{"archetype":"maker","duration_ms":120000,"tokens":3000}}
|
||||||
|
{"ts":"2026-04-03T10:04:00Z","run_id":"dag-run","seq":5,"parent":[4],"type":"run.complete","phase":"act","agent":null,"data":{"agents_total":2,"fixes_total":0}}
|
||||||
|
EVENTS
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "dag: exits 1 with usage when called with no args" {
|
||||||
|
run "$LIB_DIR/archeflow-dag.sh"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "dag: exits 1 when events file not found" {
|
||||||
|
run "$LIB_DIR/archeflow-dag.sh" nonexistent.jsonl
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"not found"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "dag: renders run.start as root node" {
|
||||||
|
run "$LIB_DIR/archeflow-dag.sh" "$BATS_TEST_TMPDIR/dag-events.jsonl" --no-color
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"#1"* ]]
|
||||||
|
[[ "$output" == *"run.start"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "dag: renders agent.complete events with archetype name" {
|
||||||
|
run "$LIB_DIR/archeflow-dag.sh" "$BATS_TEST_TMPDIR/dag-events.jsonl" --no-color
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"creator"* ]]
|
||||||
|
[[ "$output" == *"maker"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "dag: renders phase transitions" {
|
||||||
|
run "$LIB_DIR/archeflow-dag.sh" "$BATS_TEST_TMPDIR/dag-events.jsonl" --no-color
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"plan"* ]]
|
||||||
|
[[ "$output" == *"do"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "dag: renders run.complete with agent/fix counts" {
|
||||||
|
run "$LIB_DIR/archeflow-dag.sh" "$BATS_TEST_TMPDIR/dag-events.jsonl" --no-color
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"run.complete"* ]]
|
||||||
|
[[ "$output" == *"2 agents"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "dag: --no-color suppresses ANSI codes" {
|
||||||
|
run "$LIB_DIR/archeflow-dag.sh" "$BATS_TEST_TMPDIR/dag-events.jsonl" --no-color
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
# Should not contain escape sequences
|
||||||
|
[[ "$output" != *$'\033'* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "dag: uses tree-drawing characters for hierarchy" {
|
||||||
|
run "$LIB_DIR/archeflow-dag.sh" "$BATS_TEST_TMPDIR/dag-events.jsonl" --no-color
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
# Should contain box-drawing characters (either unicode or ASCII connectors)
|
||||||
|
[[ "$output" == *"├"* ]] || [[ "$output" == *"└"* ]]
|
||||||
|
}
|
||||||
127
tests/archeflow-event.bats
Normal file
127
tests/archeflow-event.bats
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# Tests for archeflow-event.sh — structured JSONL event logging.
|
||||||
|
#
|
||||||
|
# Validates: JSONL output format, sequence numbering, parent field handling,
|
||||||
|
# input validation, file/directory creation.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
_common_teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: exits 1 with usage when called with fewer than 4 args" {
|
||||||
|
run "$LIB_DIR/archeflow-event.sh" run1 type1 plan
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: creates events directory and file on first call" {
|
||||||
|
run "$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{"task":"test"}'
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ -d ".archeflow/events" ]
|
||||||
|
[ -f ".archeflow/events/test-run.jsonl" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: first event has seq=1" {
|
||||||
|
run "$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{"task":"test"}'
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
local seq
|
||||||
|
seq=$(head -1 ".archeflow/events/test-run.jsonl" | jq -r '.seq')
|
||||||
|
[ "$seq" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: second event has seq=2" {
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{"task":"test"}' 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run agent.complete plan creator '{"dur":100}' "1" 2>/dev/null
|
||||||
|
local count
|
||||||
|
count=$(wc -l < ".archeflow/events/test-run.jsonl")
|
||||||
|
[ "$count" -eq 2 ]
|
||||||
|
local seq2
|
||||||
|
seq2=$(tail -1 ".archeflow/events/test-run.jsonl" | jq -r '.seq')
|
||||||
|
[ "$seq2" -eq 2 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: output is valid JSONL" {
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{"task":"hello"}' 2>/dev/null
|
||||||
|
# jq will fail if the line is not valid JSON
|
||||||
|
jq empty ".archeflow/events/test-run.jsonl"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: fields are correctly populated" {
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run agent.complete do maker '{"tokens":500}' 2>/dev/null
|
||||||
|
local event
|
||||||
|
event=$(head -1 ".archeflow/events/test-run.jsonl")
|
||||||
|
[ "$(echo "$event" | jq -r '.run_id')" = "test-run" ]
|
||||||
|
[ "$(echo "$event" | jq -r '.type')" = "agent.complete" ]
|
||||||
|
[ "$(echo "$event" | jq -r '.phase')" = "do" ]
|
||||||
|
[ "$(echo "$event" | jq -r '.agent')" = "maker" ]
|
||||||
|
[ "$(echo "$event" | jq -r '.data.tokens')" = "500" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: empty agent becomes null in JSON" {
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run phase.transition do "" '{"from":"plan","to":"do"}' 2>/dev/null
|
||||||
|
local agent
|
||||||
|
agent=$(head -1 ".archeflow/events/test-run.jsonl" | jq -r '.agent')
|
||||||
|
[ "$agent" = "null" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: parent field is empty array for root events" {
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{}' 2>/dev/null
|
||||||
|
local parent
|
||||||
|
parent=$(head -1 ".archeflow/events/test-run.jsonl" | jq -c '.parent')
|
||||||
|
[ "$parent" = "[]" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: single parent is parsed correctly" {
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{}' 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run agent.complete plan creator '{}' "1" 2>/dev/null
|
||||||
|
local parent
|
||||||
|
parent=$(tail -1 ".archeflow/events/test-run.jsonl" | jq -c '.parent')
|
||||||
|
[ "$parent" = "[1]" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: multiple parents (fan-in) are parsed correctly" {
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{}' 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run a plan "" '{}' "1" 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run b plan "" '{}' "1" 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run merge plan "" '{}' "2,3" 2>/dev/null
|
||||||
|
local parent
|
||||||
|
parent=$(tail -1 ".archeflow/events/test-run.jsonl" | jq -c '.parent')
|
||||||
|
[ "$parent" = "[2,3]" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: rejects invalid JSON data" {
|
||||||
|
run "$LIB_DIR/archeflow-event.sh" test-run run.start plan "" 'not-json'
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"invalid JSON"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: rejects invalid parent format" {
|
||||||
|
run "$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{}' "abc"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"invalid parent format"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: timestamp is ISO 8601 UTC format" {
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{}' 2>/dev/null
|
||||||
|
local ts
|
||||||
|
ts=$(head -1 ".archeflow/events/test-run.jsonl" | jq -r '.ts')
|
||||||
|
# Matches YYYY-MM-DDTHH:MM:SSZ
|
||||||
|
[[ "$ts" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: default data is empty object when omitted" {
|
||||||
|
"$LIB_DIR/archeflow-event.sh" test-run run.start plan agent 2>/dev/null
|
||||||
|
local data
|
||||||
|
data=$(head -1 ".archeflow/events/test-run.jsonl" | jq -c '.data')
|
||||||
|
[ "$data" = "{}" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "event: confirmation message goes to stderr" {
|
||||||
|
run "$LIB_DIR/archeflow-event.sh" test-run run.start plan "" '{}' "" 2>&1
|
||||||
|
[[ "$output" == *"[archeflow-event]"* ]]
|
||||||
|
[[ "$output" == *"#1"* ]]
|
||||||
|
}
|
||||||
212
tests/archeflow-git.bats
Normal file
212
tests/archeflow-git.bats
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
# Tests for archeflow-git.sh — git branch/commit strategy for ArcheFlow runs.
|
||||||
|
#
|
||||||
|
# Validates: branch creation with correct naming, commit formatting,
|
||||||
|
# merge strategies, input validation, and safety guards.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
_common_teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Usage ---
|
||||||
|
|
||||||
|
@test "git: exits 1 with usage when called with fewer than 2 args" {
|
||||||
|
run "$LIB_DIR/archeflow-git.sh"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git: exits 1 for unknown command" {
|
||||||
|
run "$LIB_DIR/archeflow-git.sh" nonexistent test-run
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"Unknown command"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- init ---
|
||||||
|
|
||||||
|
@test "git init: creates branch with archeflow/ prefix" {
|
||||||
|
run "$LIB_DIR/archeflow-git.sh" init test-run
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
local current
|
||||||
|
current=$(git branch --show-current)
|
||||||
|
[ "$current" = "archeflow/test-run" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git init: stores base branch in .archeflow/runs/<run_id>/base-branch" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
[ -f ".archeflow/runs/test-run/base-branch" ]
|
||||||
|
local base
|
||||||
|
base=$(cat ".archeflow/runs/test-run/base-branch")
|
||||||
|
[ "$base" = "main" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git init: fails if branch already exists" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
git checkout main --quiet
|
||||||
|
run "$LIB_DIR/archeflow-git.sh" init test-run
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"already exists"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- commit ---
|
||||||
|
|
||||||
|
@test "git commit: uses conventional commit format by default" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
# Create a file to commit
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||||
|
"$LIB_DIR/archeflow-git.sh" commit test-run plan "initial plan" 2>/dev/null
|
||||||
|
local msg
|
||||||
|
msg=$(git log -1 --format=%s)
|
||||||
|
[[ "$msg" == "archeflow(plan): initial plan" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git commit: stages event file automatically" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||||
|
"$LIB_DIR/archeflow-git.sh" commit test-run plan "test commit" 2>/dev/null
|
||||||
|
|
||||||
|
# Verify the event file was committed
|
||||||
|
local committed_files
|
||||||
|
committed_files=$(git diff-tree --no-commit-id --name-only -r HEAD)
|
||||||
|
[[ "$committed_files" == *"test-run.jsonl"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git commit: stages extra files passed as arguments" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
echo "extra content" > extra.txt
|
||||||
|
"$LIB_DIR/archeflow-git.sh" commit test-run do "with extras" extra.txt 2>/dev/null
|
||||||
|
local committed_files
|
||||||
|
committed_files=$(git diff-tree --no-commit-id --name-only -r HEAD)
|
||||||
|
[[ "$committed_files" == *"extra.txt"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git commit: reports nothing to commit when no changes" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
# Commit the init artifacts first so there's a clean state
|
||||||
|
git add -A && git commit -m "init artifacts" --quiet 2>/dev/null || true
|
||||||
|
run bash -c "cd '$BATS_TEST_TMPDIR' && '$LIB_DIR/archeflow-git.sh' commit test-run plan 'empty' 2>&1"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"Nothing to commit"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git commit: fails if not on the run branch" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
git checkout main --quiet
|
||||||
|
run "$LIB_DIR/archeflow-git.sh" commit test-run plan "wrong branch"
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"Expected to be on branch"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- phase-commit ---
|
||||||
|
|
||||||
|
@test "git phase-commit: creates commit with phase transition message" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||||
|
"$LIB_DIR/archeflow-git.sh" phase-commit test-run plan 2>/dev/null
|
||||||
|
local msg
|
||||||
|
msg=$(git log -1 --format=%s)
|
||||||
|
# Should contain the phase transition arrow
|
||||||
|
[[ "$msg" == *"plan"* ]]
|
||||||
|
[[ "$msg" == *"do"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- merge ---
|
||||||
|
|
||||||
|
@test "git merge: squash merge is the default strategy" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||||
|
"$LIB_DIR/archeflow-git.sh" commit test-run plan "test" 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-git.sh" merge test-run 2>/dev/null
|
||||||
|
|
||||||
|
local current
|
||||||
|
current=$(git branch --show-current)
|
||||||
|
[ "$current" = "main" ]
|
||||||
|
|
||||||
|
local msg
|
||||||
|
msg=$(git log -1 --format=%s)
|
||||||
|
[[ "$msg" == *"archeflow run test-run"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git merge: --no-ff creates a merge commit" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||||
|
"$LIB_DIR/archeflow-git.sh" commit test-run plan "test" 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-git.sh" merge test-run --no-ff 2>/dev/null
|
||||||
|
|
||||||
|
local current
|
||||||
|
current=$(git branch --show-current)
|
||||||
|
[ "$current" = "main" ]
|
||||||
|
|
||||||
|
# no-ff merge commit should have 2 parents
|
||||||
|
local parent_count
|
||||||
|
parent_count=$(git cat-file -p HEAD | grep -c '^parent')
|
||||||
|
[ "$parent_count" -eq 2 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git merge: rejects unknown merge strategy" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||||
|
"$LIB_DIR/archeflow-git.sh" commit test-run plan "test" 2>/dev/null
|
||||||
|
run "$LIB_DIR/archeflow-git.sh" merge test-run --fast-forward
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"Unknown merge strategy"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git merge: fails with uncommitted changes" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
echo "dirty" > dirty.txt
|
||||||
|
git add dirty.txt
|
||||||
|
run "$LIB_DIR/archeflow-git.sh" merge test-run
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"Uncommitted changes"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- format_message ---
|
||||||
|
|
||||||
|
@test "git commit: simple style uses 'phase: msg' format" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
# Create config with simple style
|
||||||
|
mkdir -p .archeflow
|
||||||
|
echo "commit_style: simple" > .archeflow/config.yaml
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
echo '{"test":true}' > .archeflow/events/test-run.jsonl
|
||||||
|
"$LIB_DIR/archeflow-git.sh" commit test-run plan "simple test" 2>/dev/null
|
||||||
|
local msg
|
||||||
|
msg=$(git log -1 --format=%s)
|
||||||
|
[ "$msg" = "plan: simple test" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- status ---
|
||||||
|
|
||||||
|
@test "git status: shows branch info for existing run" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
run "$LIB_DIR/archeflow-git.sh" status test-run
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"Branch: archeflow/test-run"* ]]
|
||||||
|
[[ "$output" == *"Base: main"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "git status: fails for nonexistent branch" {
|
||||||
|
run "$LIB_DIR/archeflow-git.sh" status nonexistent
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"does not exist"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- cleanup ---
|
||||||
|
|
||||||
|
@test "git cleanup: fails if currently on the run branch" {
|
||||||
|
"$LIB_DIR/archeflow-git.sh" init test-run 2>/dev/null
|
||||||
|
run "$LIB_DIR/archeflow-git.sh" cleanup test-run
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"Cannot delete"* ]]
|
||||||
|
}
|
||||||
81
tests/archeflow-init.bats
Normal file
81
tests/archeflow-init.bats
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# Tests for archeflow-init.sh — project initialization from templates.
|
||||||
|
#
|
||||||
|
# Validates: usage output, --list, --from (clone), and argument parsing.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
_common_teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "init: shows usage when called with no args" {
|
||||||
|
run "$LIB_DIR/archeflow-init.sh"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
[[ "$output" == *"bundle-name"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "init: --list shows template listing without errors" {
|
||||||
|
run "$LIB_DIR/archeflow-init.sh" --list
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"Templates"* ]]
|
||||||
|
[[ "$output" == *"Bundles"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "init: --from fails when source has no .archeflow dir" {
|
||||||
|
local source_dir
|
||||||
|
source_dir=$(mktemp -d)
|
||||||
|
run "$LIB_DIR/archeflow-init.sh" --from "$source_dir"
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"No .archeflow/"* ]]
|
||||||
|
rm -rf "$source_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "init: --from clones setup from another project" {
|
||||||
|
# Create a source project with .archeflow structure
|
||||||
|
local source_dir
|
||||||
|
source_dir=$(mktemp -d)
|
||||||
|
mkdir -p "$source_dir/.archeflow/teams" "$source_dir/.archeflow/workflows"
|
||||||
|
echo "name: test-team" > "$source_dir/.archeflow/teams/test.yaml"
|
||||||
|
echo "name: test-workflow" > "$source_dir/.archeflow/workflows/test.yaml"
|
||||||
|
echo "bundle: test" > "$source_dir/.archeflow/config.yaml"
|
||||||
|
|
||||||
|
run "$LIB_DIR/archeflow-init.sh" --from "$source_dir"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ -f ".archeflow/teams/test.yaml" ]
|
||||||
|
[ -f ".archeflow/workflows/test.yaml" ]
|
||||||
|
[ -f ".archeflow/config.yaml" ]
|
||||||
|
rm -rf "$source_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "init: --from skips events and artifacts directories" {
|
||||||
|
local source_dir
|
||||||
|
source_dir=$(mktemp -d)
|
||||||
|
mkdir -p "$source_dir/.archeflow/events" "$source_dir/.archeflow/artifacts"
|
||||||
|
mkdir -p "$source_dir/.archeflow/teams"
|
||||||
|
echo "name: test" > "$source_dir/.archeflow/teams/t.yaml"
|
||||||
|
echo '{"test":true}' > "$source_dir/.archeflow/events/run.jsonl"
|
||||||
|
echo "artifact" > "$source_dir/.archeflow/artifacts/test.txt"
|
||||||
|
|
||||||
|
run "$LIB_DIR/archeflow-init.sh" --from "$source_dir"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ ! -f ".archeflow/events/run.jsonl" ]
|
||||||
|
[ ! -f ".archeflow/artifacts/test.txt" ]
|
||||||
|
[[ "$output" == *"skipped events"* ]]
|
||||||
|
rm -rf "$source_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "init: rejects unknown options" {
|
||||||
|
run "$LIB_DIR/archeflow-init.sh" --nonexistent
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"Unknown option"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "init: --save fails with no .archeflow directory" {
|
||||||
|
run "$LIB_DIR/archeflow-init.sh" --save test-save
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"No .archeflow/"* ]]
|
||||||
|
}
|
||||||
227
tests/archeflow-memory.bats
Normal file
227
tests/archeflow-memory.bats
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
# Tests for archeflow-memory.sh — cross-run lesson memory management.
|
||||||
|
#
|
||||||
|
# Validates: add, list, decay, forget, inject filtering, and JSONL format.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
_common_teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Usage / error handling ---
|
||||||
|
|
||||||
|
@test "memory: exits 1 with usage when called with no args" {
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory: exits 1 for unknown command" {
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" nonexistent
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Unknown command"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- add ---
|
||||||
|
|
||||||
|
@test "memory add: creates lessons.jsonl and appends a valid JSONL line" {
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" add preference "Always validate inputs"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ -f ".archeflow/memory/lessons.jsonl" ]
|
||||||
|
jq empty ".archeflow/memory/lessons.jsonl"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory add: lesson has correct fields" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "Guardian misses SQL injection" 2>/dev/null
|
||||||
|
[ "$(jq -r '.type' .archeflow/memory/lessons.jsonl)" = "pattern" ]
|
||||||
|
[ "$(jq -r '.description' .archeflow/memory/lessons.jsonl)" = "Guardian misses SQL injection" ]
|
||||||
|
[ "$(jq -r '.source' .archeflow/memory/lessons.jsonl)" = "user_feedback" ]
|
||||||
|
[ "$(jq -r '.frequency' .archeflow/memory/lessons.jsonl)" = "1" ]
|
||||||
|
[ "$(jq -r '.run_id' .archeflow/memory/lessons.jsonl)" = "manual" ]
|
||||||
|
[ "$(jq -r '.domain' .archeflow/memory/lessons.jsonl)" = "general" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory add: generates sequential IDs" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "first lesson" 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "second lesson" 2>/dev/null
|
||||||
|
local id1 id2
|
||||||
|
id1=$(head -1 ".archeflow/memory/lessons.jsonl" | jq -r '.id')
|
||||||
|
id2=$(tail -1 ".archeflow/memory/lessons.jsonl" | jq -r '.id')
|
||||||
|
[ "$id1" = "m-001" ]
|
||||||
|
[ "$id2" = "m-002" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory add: generates tags from description" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "Guardian misses SQL injection attacks" 2>/dev/null
|
||||||
|
local tags_count
|
||||||
|
tags_count=$(head -1 ".archeflow/memory/lessons.jsonl" | jq '.tags | length')
|
||||||
|
[ "$tags_count" -gt 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory add: exits 1 when description is missing" {
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" add pattern
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- list ---
|
||||||
|
|
||||||
|
@test "memory list: shows message when no lessons exist" {
|
||||||
|
run bash -c "'$LIB_DIR/archeflow-memory.sh' list 2>&1"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"No lessons"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory list: shows table header and lesson data" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "Test lesson for listing" 2>/dev/null
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" list
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"ID"* ]]
|
||||||
|
[[ "$output" == *"Freq"* ]]
|
||||||
|
[[ "$output" == *"m-001"* ]]
|
||||||
|
[[ "$output" == *"Test lesson for listing"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- decay ---
|
||||||
|
|
||||||
|
@test "memory decay: increments runs_since_last_seen" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "Decay test lesson" 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" decay 2>/dev/null
|
||||||
|
local runs_since
|
||||||
|
runs_since=$(head -1 ".archeflow/memory/lessons.jsonl" | jq '.runs_since_last_seen')
|
||||||
|
[ "$runs_since" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory decay: decrements frequency after 10 runs" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "Decay frequency test" 2>/dev/null
|
||||||
|
# Set frequency=3 and runs_since=9 to trigger decay on next call
|
||||||
|
local tmp=".archeflow/memory/lessons.jsonl.tmp"
|
||||||
|
head -1 ".archeflow/memory/lessons.jsonl" | jq -c '.frequency = 3 | .runs_since_last_seen = 9' > "$tmp"
|
||||||
|
mv "$tmp" ".archeflow/memory/lessons.jsonl"
|
||||||
|
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" decay 2>/dev/null
|
||||||
|
local freq
|
||||||
|
freq=$(head -1 ".archeflow/memory/lessons.jsonl" | jq '.frequency')
|
||||||
|
[ "$freq" -eq 2 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory decay: archives lesson when frequency reaches 0" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "Will be archived" 2>/dev/null
|
||||||
|
# Set frequency=1 and runs_since=9 to trigger archival
|
||||||
|
local tmp=".archeflow/memory/lessons.jsonl.tmp"
|
||||||
|
head -1 ".archeflow/memory/lessons.jsonl" | jq -c '.frequency = 1 | .runs_since_last_seen = 9' > "$tmp"
|
||||||
|
mv "$tmp" ".archeflow/memory/lessons.jsonl"
|
||||||
|
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" decay 2>/dev/null
|
||||||
|
|
||||||
|
# Lesson should be gone from lessons file (file should be empty)
|
||||||
|
local remaining
|
||||||
|
remaining=$(wc -l < ".archeflow/memory/lessons.jsonl" | tr -d ' ')
|
||||||
|
[ "$remaining" -eq 0 ]
|
||||||
|
|
||||||
|
# And present in archive
|
||||||
|
[ -f ".archeflow/memory/archive.jsonl" ]
|
||||||
|
local archived_count
|
||||||
|
archived_count=$(wc -l < ".archeflow/memory/archive.jsonl" | tr -d ' ')
|
||||||
|
[ "$archived_count" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory decay: does nothing when no lessons exist" {
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" decay
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- forget ---
|
||||||
|
|
||||||
|
@test "memory forget: moves lesson to archive" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "Will forget this" 2>/dev/null
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" forget m-001 2>/dev/null
|
||||||
|
|
||||||
|
# Lessons file should be empty
|
||||||
|
local remaining
|
||||||
|
remaining=$(wc -l < ".archeflow/memory/lessons.jsonl" | tr -d ' ')
|
||||||
|
[ "$remaining" -eq 0 ]
|
||||||
|
|
||||||
|
# Archive should have it
|
||||||
|
[ -f ".archeflow/memory/archive.jsonl" ]
|
||||||
|
local archived_id
|
||||||
|
archived_id=$(head -1 ".archeflow/memory/archive.jsonl" | jq -r '.id')
|
||||||
|
[ "$archived_id" = "m-001" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory forget: exits 1 for nonexistent ID" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "test" 2>/dev/null
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" forget m-999
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"not found"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory forget: exits 1 when no lessons file exists" {
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" forget m-001
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"No lessons file"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- inject ---
|
||||||
|
|
||||||
|
@test "memory inject: outputs nothing when no lessons file exists" {
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" inject code guardian
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ -z "$output" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory inject: outputs relevant lessons with frequency >= 2" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "Test injection lesson" 2>/dev/null
|
||||||
|
# Bump frequency to 2
|
||||||
|
local tmp=".archeflow/memory/lessons.jsonl.tmp"
|
||||||
|
jq -c '.frequency = 2' ".archeflow/memory/lessons.jsonl" > "$tmp"
|
||||||
|
mv "$tmp" ".archeflow/memory/lessons.jsonl"
|
||||||
|
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" inject "" ""
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"Known Issues"* ]]
|
||||||
|
[[ "$output" == *"Test injection lesson"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory inject: skips lessons with frequency < 2 (except preferences)" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add pattern "Low frequency lesson" 2>/dev/null
|
||||||
|
# frequency is 1 by default, type is pattern -> should NOT be injected
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" inject "" ""
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ -z "$output" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory inject: always injects preferences regardless of frequency" {
|
||||||
|
"$LIB_DIR/archeflow-memory.sh" add preference "User prefers explicit error messages" 2>/dev/null
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" inject "" ""
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"User prefers explicit error messages"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- extract ---
|
||||||
|
|
||||||
|
@test "memory extract: exits 1 when events file not found" {
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" extract nonexistent.jsonl
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"not found"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "memory extract: extracts findings from review.verdict events" {
|
||||||
|
# Create a mock events file with a review.verdict
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
cat > /tmp/test-events.jsonl <<'EOF'
|
||||||
|
{"run_id":"test-run","seq":1,"type":"run.start","phase":"plan","data":{"task":"test"}}
|
||||||
|
{"run_id":"test-run","seq":2,"type":"review.verdict","phase":"check","data":{"archetype":"guardian","verdict":"needs_changes","findings":[{"severity":"warning","description":"Missing input validation on user endpoint","category":"code"}]}}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
run "$LIB_DIR/archeflow-memory.sh" extract /tmp/test-events.jsonl
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ -f ".archeflow/memory/lessons.jsonl" ]
|
||||||
|
local desc
|
||||||
|
desc=$(jq -r '.description' ".archeflow/memory/lessons.jsonl")
|
||||||
|
[[ "$desc" == *"Missing input validation"* ]]
|
||||||
|
rm -f /tmp/test-events.jsonl
|
||||||
|
}
|
||||||
78
tests/archeflow-progress.bats
Normal file
78
tests/archeflow-progress.bats
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# Tests for archeflow-progress.sh — live progress file generation.
|
||||||
|
#
|
||||||
|
# Validates: markdown output structure, JSON mode, missing events handling, exit codes.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
|
||||||
|
# Create standard events for progress tests
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
cat > ".archeflow/events/test-run.jsonl" <<'EVENTS'
|
||||||
|
{"ts":"2026-04-03T10:00:00Z","run_id":"test-run","seq":1,"parent":[],"type":"run.start","phase":"plan","agent":null,"data":{"task":"Build feature","workflow":"standard","team":"default"}}
|
||||||
|
{"ts":"2026-04-03T10:01:00Z","run_id":"test-run","seq":2,"parent":[1],"type":"agent.complete","phase":"plan","agent":"creator","data":{"archetype":"creator","duration_ms":60000,"tokens":1500,"estimated_cost_usd":0.02,"summary":"Planned"}}
|
||||||
|
EVENTS
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "progress: exits 1 with usage when called with no args" {
|
||||||
|
run "$LIB_DIR/archeflow-progress.sh"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "progress: exits 1 when events file not found" {
|
||||||
|
run "$LIB_DIR/archeflow-progress.sh" nonexistent-run
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"not found"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "progress: default mode generates progress.md" {
|
||||||
|
run "$LIB_DIR/archeflow-progress.sh" test-run
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ -f ".archeflow/progress.md" ]
|
||||||
|
[[ "$output" == *"# ArcheFlow Run: test-run"* ]]
|
||||||
|
[[ "$output" == *"Status:"* ]]
|
||||||
|
[[ "$output" == *"Progress"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "progress: json mode outputs valid JSON" {
|
||||||
|
run "$LIB_DIR/archeflow-progress.sh" test-run --json
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
echo "$output" | jq empty
|
||||||
|
local run_id
|
||||||
|
run_id=$(echo "$output" | jq -r '.run_id')
|
||||||
|
[ "$run_id" = "test-run" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "progress: json mode includes completed agents" {
|
||||||
|
run "$LIB_DIR/archeflow-progress.sh" test-run --json
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
local completed_count
|
||||||
|
completed_count=$(echo "$output" | jq '.completed | length')
|
||||||
|
[ "$completed_count" -eq 1 ]
|
||||||
|
local agent
|
||||||
|
agent=$(echo "$output" | jq -r '.completed[0].agent')
|
||||||
|
[ "$agent" = "creator" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "progress: json mode shows correct phase" {
|
||||||
|
run "$LIB_DIR/archeflow-progress.sh" test-run --json
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
local phase
|
||||||
|
phase=$(echo "$output" | jq -r '.phase')
|
||||||
|
[ "$phase" = "plan" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "progress: reports error in json when events file missing" {
|
||||||
|
run "$LIB_DIR/archeflow-progress.sh" missing-run --json
|
||||||
|
# JSON mode returns the JSON even on error
|
||||||
|
local error
|
||||||
|
error=$(echo "$output" | jq -r '.error // empty')
|
||||||
|
[[ "$error" == *"not found"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "progress: rejects unknown flags" {
|
||||||
|
run "$LIB_DIR/archeflow-progress.sh" test-run --invalid
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Unknown flag"* ]]
|
||||||
|
}
|
||||||
80
tests/archeflow-report.bats
Normal file
80
tests/archeflow-report.bats
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# Tests for archeflow-report.sh — Markdown process report generation from JSONL events.
|
||||||
|
#
|
||||||
|
# Validates: report output format, summary mode, missing file handling, jq dependency check.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
|
||||||
|
# Create a standard events file used by multiple tests
|
||||||
|
mkdir -p .archeflow/events
|
||||||
|
cat > "$BATS_TEST_TMPDIR/events.jsonl" <<'EVENTS'
|
||||||
|
{"ts":"2026-04-03T10:00:00Z","run_id":"test-run","seq":1,"parent":[],"type":"run.start","phase":"plan","agent":null,"data":{"task":"Write unit tests","workflow":"standard","team":"default"}}
|
||||||
|
{"ts":"2026-04-03T10:01:00Z","run_id":"test-run","seq":2,"parent":[1],"type":"agent.complete","phase":"plan","agent":"creator","data":{"archetype":"creator","duration_ms":60000,"tokens":1500,"summary":"Designed test structure"}}
|
||||||
|
{"ts":"2026-04-03T10:02:00Z","run_id":"test-run","seq":3,"parent":[2],"type":"phase.transition","phase":"do","agent":null,"data":{"from":"plan","to":"do"}}
|
||||||
|
{"ts":"2026-04-03T10:05:00Z","run_id":"test-run","seq":4,"parent":[3],"type":"agent.complete","phase":"do","agent":"maker","data":{"archetype":"maker","duration_ms":180000,"tokens":3000,"summary":"Implemented tests"}}
|
||||||
|
{"ts":"2026-04-03T10:06:00Z","run_id":"test-run","seq":5,"parent":[4],"type":"phase.transition","phase":"check","agent":null,"data":{"from":"do","to":"check"}}
|
||||||
|
{"ts":"2026-04-03T10:07:00Z","run_id":"test-run","seq":6,"parent":[5],"type":"review.verdict","phase":"check","agent":"guardian","data":{"archetype":"guardian","verdict":"approved","findings":[]}}
|
||||||
|
{"ts":"2026-04-03T10:08:00Z","run_id":"test-run","seq":7,"parent":[6],"type":"run.complete","phase":"act","agent":null,"data":{"status":"completed","cycles":1,"agents_total":3,"fixes_total":0,"duration_ms":480000}}
|
||||||
|
EVENTS
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "report: exits 1 with usage when called with no args" {
|
||||||
|
run "$LIB_DIR/archeflow-report.sh"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "report: exits 1 when events file not found" {
|
||||||
|
run "$LIB_DIR/archeflow-report.sh" nonexistent.jsonl
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"not found"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "report: full mode produces markdown with header and overview" {
|
||||||
|
run "$LIB_DIR/archeflow-report.sh" "$BATS_TEST_TMPDIR/events.jsonl"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"# Process Report: Write unit tests"* ]]
|
||||||
|
[[ "$output" == *"test-run"* ]]
|
||||||
|
[[ "$output" == *"Overview"* ]]
|
||||||
|
[[ "$output" == *"Status"* ]]
|
||||||
|
[[ "$output" == *"completed"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "report: full mode includes phase sections" {
|
||||||
|
run "$LIB_DIR/archeflow-report.sh" "$BATS_TEST_TMPDIR/events.jsonl"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"PLAN"* ]]
|
||||||
|
[[ "$output" == *"DO"* ]]
|
||||||
|
[[ "$output" == *"CHECK"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "report: summary mode outputs one-line summary" {
|
||||||
|
run "$LIB_DIR/archeflow-report.sh" "$BATS_TEST_TMPDIR/events.jsonl" --summary
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
# Should be a single logical line with key stats
|
||||||
|
[[ "$output" == *"[completed]"* ]]
|
||||||
|
[[ "$output" == *"Write unit tests"* ]]
|
||||||
|
[[ "$output" == *"1 cycles"* ]]
|
||||||
|
[[ "$output" == *"test-run"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "report: --output writes to file instead of stdout" {
|
||||||
|
run "$LIB_DIR/archeflow-report.sh" "$BATS_TEST_TMPDIR/events.jsonl" --output "$BATS_TEST_TMPDIR/report.md"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ -f "$BATS_TEST_TMPDIR/report.md" ]
|
||||||
|
local content
|
||||||
|
content=$(cat "$BATS_TEST_TMPDIR/report.md")
|
||||||
|
[[ "$content" == *"# Process Report"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "report: summary for in-progress run shows [in-progress]" {
|
||||||
|
# Events file without run.complete
|
||||||
|
cat > "$BATS_TEST_TMPDIR/in-progress.jsonl" <<'EVENTS'
|
||||||
|
{"ts":"2026-04-03T10:00:00Z","run_id":"wip-run","seq":1,"parent":[],"type":"run.start","phase":"plan","agent":null,"data":{"task":"WIP task","workflow":"fast","team":"default"}}
|
||||||
|
EVENTS
|
||||||
|
run "$LIB_DIR/archeflow-report.sh" "$BATS_TEST_TMPDIR/in-progress.jsonl" --summary
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"[in-progress]"* ]]
|
||||||
|
[[ "$output" == *"WIP task"* ]]
|
||||||
|
}
|
||||||
82
tests/archeflow-review.bats
Normal file
82
tests/archeflow-review.bats
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# Tests for archeflow-review.sh — git diff extraction for code review.
|
||||||
|
#
|
||||||
|
# Validates: argument parsing, diff modes, stats output, empty diff handling.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
_common_teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "review: --help shows usage" {
|
||||||
|
run "$LIB_DIR/archeflow-review.sh" --help
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
[[ "$output" == *"--branch"* ]]
|
||||||
|
[[ "$output" == *"--commit"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "review: exits 1 when no changes to review" {
|
||||||
|
run "$LIB_DIR/archeflow-review.sh"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"No changes"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "review: shows diff for uncommitted changes" {
|
||||||
|
echo "new content" > testfile.txt
|
||||||
|
git add testfile.txt
|
||||||
|
run "$LIB_DIR/archeflow-review.sh"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"testfile.txt"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "review: --stat-only prints stats without diff content" {
|
||||||
|
echo "stat content" > statfile.txt
|
||||||
|
git add statfile.txt
|
||||||
|
run "$LIB_DIR/archeflow-review.sh" --stat-only
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
# stderr has stats, stdout should be empty (no diff)
|
||||||
|
# But run captures both, so just check it ran ok
|
||||||
|
[[ "$output" == *"Review Stats"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "review: --branch fails for nonexistent branch" {
|
||||||
|
run "$LIB_DIR/archeflow-review.sh" --branch nonexistent-branch-xyz
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"not found"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "review: rejects unknown arguments" {
|
||||||
|
run "$LIB_DIR/archeflow-review.sh" --unknown
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"Unknown argument"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "review: --branch shows diff against base" {
|
||||||
|
# Create a feature branch with changes
|
||||||
|
git checkout -b feat/test-review --quiet
|
||||||
|
echo "feature" > feature.txt
|
||||||
|
git add feature.txt
|
||||||
|
git commit -m "feat: add feature" --quiet
|
||||||
|
git checkout main --quiet
|
||||||
|
|
||||||
|
run "$LIB_DIR/archeflow-review.sh" --branch feat/test-review
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"feature.txt"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "review: --commit shows diff for commit range" {
|
||||||
|
echo "first" > first.txt
|
||||||
|
git add first.txt
|
||||||
|
git commit -m "first" --quiet
|
||||||
|
echo "second" > second.txt
|
||||||
|
git add second.txt
|
||||||
|
git commit -m "second" --quiet
|
||||||
|
|
||||||
|
run "$LIB_DIR/archeflow-review.sh" --commit HEAD~1..HEAD
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"second.txt"* ]]
|
||||||
|
}
|
||||||
58
tests/archeflow-rollback.bats
Normal file
58
tests/archeflow-rollback.bats
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Tests for archeflow-rollback.sh — post-merge test and phase rollback.
|
||||||
|
#
|
||||||
|
# Validates: argument parsing, mutual exclusivity, phase validation, test-cmd config reading.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
_common_teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "rollback: exits with error when called with no args" {
|
||||||
|
run "$LIB_DIR/archeflow-rollback.sh"
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "rollback: rejects mutually exclusive --to and --test-cmd" {
|
||||||
|
run "$LIB_DIR/archeflow-rollback.sh" test-run --to plan --test-cmd "true"
|
||||||
|
[ "$status" -eq 2 ]
|
||||||
|
[[ "$output" == *"mutually exclusive"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "rollback: rejects invalid phase names" {
|
||||||
|
run "$LIB_DIR/archeflow-rollback.sh" test-run --to invalid-phase
|
||||||
|
[ "$status" -eq 2 ]
|
||||||
|
[[ "$output" == *"Invalid phase"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "rollback: accepts valid phase names (plan, do, check)" {
|
||||||
|
# This will fail because no git branch exists, but should NOT fail on phase validation
|
||||||
|
run "$LIB_DIR/archeflow-rollback.sh" test-run --to plan
|
||||||
|
# Should fail later (archeflow-git.sh rollback) not on phase validation
|
||||||
|
[[ "$output" != *"Invalid phase"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "rollback: exits 2 when no test command available" {
|
||||||
|
run "$LIB_DIR/archeflow-rollback.sh" test-run
|
||||||
|
[ "$status" -eq 2 ]
|
||||||
|
[[ "$output" == *"No test command"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "rollback: reads test_command from config.yaml" {
|
||||||
|
mkdir -p .archeflow
|
||||||
|
echo 'test_command: "echo ok"' > .archeflow/config.yaml
|
||||||
|
# HEAD won't have archeflow in its message, but the script just warns and proceeds
|
||||||
|
run "$LIB_DIR/archeflow-rollback.sh" test-run
|
||||||
|
# It should pick up the command and try to run it (test should pass -> exit 0)
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"Tests passed"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "rollback: rejects unknown options" {
|
||||||
|
run "$LIB_DIR/archeflow-rollback.sh" test-run --unknown-flag
|
||||||
|
[ "$status" -eq 2 ]
|
||||||
|
[[ "$output" == *"Unknown option"* ]]
|
||||||
|
}
|
||||||
105
tests/archeflow-score.bats
Normal file
105
tests/archeflow-score.bats
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# Tests for archeflow-score.sh — archetype effectiveness scoring.
|
||||||
|
#
|
||||||
|
# Validates: score extraction from events, report generation, input validation.
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
load test_helper
|
||||||
|
_common_setup
|
||||||
|
|
||||||
|
# Create a complete run events file with review data
|
||||||
|
mkdir -p .archeflow/events .archeflow/memory
|
||||||
|
cat > "$BATS_TEST_TMPDIR/scored-events.jsonl" <<'EVENTS'
|
||||||
|
{"ts":"2026-04-03T10:00:00Z","run_id":"score-run","seq":1,"parent":[],"type":"run.start","phase":"plan","agent":null,"data":{"task":"Score test"}}
|
||||||
|
{"ts":"2026-04-03T10:01:00Z","run_id":"score-run","seq":2,"parent":[1],"type":"agent.complete","phase":"plan","agent":"creator","data":{"archetype":"creator","duration_ms":60000,"tokens":1500,"estimated_cost_usd":0.02}}
|
||||||
|
{"ts":"2026-04-03T10:02:00Z","run_id":"score-run","seq":3,"parent":[2],"type":"agent.complete","phase":"do","agent":"maker","data":{"archetype":"maker","duration_ms":120000,"tokens":3000,"estimated_cost_usd":0.05}}
|
||||||
|
{"ts":"2026-04-03T10:03:00Z","run_id":"score-run","seq":4,"parent":[3],"type":"review.verdict","phase":"check","agent":"guardian","data":{"archetype":"guardian","verdict":"needs_changes","findings":[{"severity":"warning","description":"Missing validation","fix_required":true},{"severity":"info","description":"Consider logging","fix_required":false}]}}
|
||||||
|
{"ts":"2026-04-03T10:03:30Z","run_id":"score-run","seq":5,"parent":[3],"type":"review.verdict","phase":"check","agent":"sage","data":{"archetype":"sage","verdict":"approved","findings":[]}}
|
||||||
|
{"ts":"2026-04-03T10:04:00Z","run_id":"score-run","seq":6,"parent":[4],"type":"fix.applied","phase":"act","agent":null,"data":{"source":"guardian","finding":"Missing validation"}}
|
||||||
|
{"ts":"2026-04-03T10:05:00Z","run_id":"score-run","seq":7,"parent":[6],"type":"cycle.boundary","phase":"act","agent":null,"data":{"cycle":1,"max_cycles":3,"met":true,"next_action":"merge"}}
|
||||||
|
{"ts":"2026-04-03T10:06:00Z","run_id":"score-run","seq":8,"parent":[7],"type":"run.complete","phase":"act","agent":null,"data":{"status":"completed","cycles":1,"agents_total":4,"fixes_total":1}}
|
||||||
|
EVENTS
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "score: exits 1 with usage when called with no args" {
|
||||||
|
run "$LIB_DIR/archeflow-score.sh"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Usage"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "score: exits 1 for unknown command" {
|
||||||
|
run "$LIB_DIR/archeflow-score.sh" nonexistent
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"Unknown command"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "score extract: exits 1 when events file not found" {
|
||||||
|
run "$LIB_DIR/archeflow-score.sh" extract nonexistent.jsonl
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"not found"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "score extract: exits 1 for incomplete run (no run.complete)" {
|
||||||
|
cat > "$BATS_TEST_TMPDIR/incomplete.jsonl" <<'EVENTS'
|
||||||
|
{"ts":"2026-04-03T10:00:00Z","run_id":"incomplete","seq":1,"parent":[],"type":"run.start","phase":"plan","agent":null,"data":{"task":"Incomplete"}}
|
||||||
|
EVENTS
|
||||||
|
run "$LIB_DIR/archeflow-score.sh" extract "$BATS_TEST_TMPDIR/incomplete.jsonl"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"run.complete"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "score extract: creates effectiveness.jsonl with archetype scores" {
|
||||||
|
run "$LIB_DIR/archeflow-score.sh" extract "$BATS_TEST_TMPDIR/scored-events.jsonl"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ -f ".archeflow/memory/effectiveness.jsonl" ]
|
||||||
|
|
||||||
|
# Should have scores for guardian and sage (the reviewers)
|
||||||
|
local guardian_score
|
||||||
|
guardian_score=$(grep '"guardian"' ".archeflow/memory/effectiveness.jsonl" | head -1)
|
||||||
|
[ -n "$guardian_score" ]
|
||||||
|
|
||||||
|
# Verify JSONL is valid
|
||||||
|
while IFS= read -r line; do
|
||||||
|
echo "$line" | jq empty
|
||||||
|
done < ".archeflow/memory/effectiveness.jsonl"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "score extract: guardian has correct finding counts" {
|
||||||
|
"$LIB_DIR/archeflow-score.sh" extract "$BATS_TEST_TMPDIR/scored-events.jsonl" 2>/dev/null
|
||||||
|
local guardian
|
||||||
|
guardian=$(grep '"guardian"' ".archeflow/memory/effectiveness.jsonl" | head -1)
|
||||||
|
local total_findings
|
||||||
|
total_findings=$(echo "$guardian" | jq '.findings_total')
|
||||||
|
[ "$total_findings" -eq 2 ]
|
||||||
|
local useful_findings
|
||||||
|
useful_findings=$(echo "$guardian" | jq '.findings_useful')
|
||||||
|
[ "$useful_findings" -eq 1 ]
|
||||||
|
local fixes
|
||||||
|
fixes=$(echo "$guardian" | jq '.fixes_applied')
|
||||||
|
[ "$fixes" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "score extract: composite score is between 0 and 1" {
|
||||||
|
"$LIB_DIR/archeflow-score.sh" extract "$BATS_TEST_TMPDIR/scored-events.jsonl" 2>/dev/null
|
||||||
|
while IFS= read -r line; do
|
||||||
|
local score
|
||||||
|
score=$(echo "$line" | jq '.composite_score')
|
||||||
|
# score >= 0 and score <= 1
|
||||||
|
[ "$(echo "$score >= 0" | bc)" -eq 1 ]
|
||||||
|
[ "$(echo "$score <= 1" | bc)" -eq 1 ]
|
||||||
|
done < ".archeflow/memory/effectiveness.jsonl"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "score report: exits 1 when no effectiveness data" {
|
||||||
|
run "$LIB_DIR/archeflow-score.sh" report
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"No effectiveness data"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "score report: outputs markdown table with archetype data" {
|
||||||
|
"$LIB_DIR/archeflow-score.sh" extract "$BATS_TEST_TMPDIR/scored-events.jsonl" 2>/dev/null
|
||||||
|
run "$LIB_DIR/archeflow-score.sh" report
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"Archetype Effectiveness Report"* ]]
|
||||||
|
[[ "$output" == *"Archetype"* ]]
|
||||||
|
[[ "$output" == *"guardian"* ]]
|
||||||
|
}
|
||||||
40
tests/test_helper.bash
Normal file
40
tests/test_helper.bash
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# test_helper.bash — Shared setup/teardown for ArcheFlow bats tests.
|
||||||
|
#
|
||||||
|
# Usage in .bats files:
|
||||||
|
# setup() { load test_helper; _common_setup; }
|
||||||
|
# teardown() { _common_teardown; }
|
||||||
|
#
|
||||||
|
# Provides:
|
||||||
|
# - BATS_TEST_TMPDIR: unique temp directory per test
|
||||||
|
# - Mock .archeflow/ structure via a git repo
|
||||||
|
# - LIB_DIR: path to the lib/ scripts under test
|
||||||
|
|
||||||
|
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../lib" && pwd)"
|
||||||
|
|
||||||
|
_common_setup() {
|
||||||
|
# Create a unique temp directory for this test
|
||||||
|
BATS_TEST_TMPDIR="$(mktemp -d)"
|
||||||
|
export BATS_TEST_TMPDIR
|
||||||
|
|
||||||
|
# Work inside the temp dir so scripts create .archeflow/ there
|
||||||
|
cd "$BATS_TEST_TMPDIR"
|
||||||
|
|
||||||
|
# Initialize a minimal git repo (many scripts need it)
|
||||||
|
git init --quiet
|
||||||
|
git config user.email "test@test.com"
|
||||||
|
git config user.name "Test User"
|
||||||
|
# Disable commit signing in tests (global config may have it enabled)
|
||||||
|
git config commit.gpgsign false
|
||||||
|
git config tag.gpgsign false
|
||||||
|
|
||||||
|
# Create an initial commit so HEAD exists
|
||||||
|
echo "init" > README.md
|
||||||
|
git add README.md
|
||||||
|
git commit -m "init" --quiet
|
||||||
|
}
|
||||||
|
|
||||||
|
_common_teardown() {
|
||||||
|
# Return to a safe directory before cleanup
|
||||||
|
cd /tmp
|
||||||
|
rm -rf "$BATS_TEST_TMPDIR"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user