Institute of English Studies · University of Łódź
A working account of how a multi-agent AI team is organised, governed, and maintained — including operating mechanics, the role of the internal auditor, and the memory architecture that lets specialist agents accumulate experience across sessions.
This document explains how a multi-agent artificial intelligence team is organised, governed, and maintained. The system described here is not a theoretical blueprint — it is a working operational framework used to coordinate specialised AI agents that perform research, writing, translation, auditing, and systems administration within a higher-education environment.
The design rests on four principles: specialisation (each agent has one clearly defined role), accountability (every action is traceable, auditable, and reversible), simplicity (complexity is permitted only when it solves a documented problem), and KISS — "Keep It Simple, Stupid" — a binding design rule inherited from Kelly Johnson at Lockheed Skunk Works in the 1960s. Under KISS, no agent, skill, workflow, or configuration may carry more complexity than its documented responsibility justifies. The result is a team that functions less like a collection of disconnected tools and more like a small research unit with explicit chains of command, memory, and quality control.
The following sections walk through the architecture from the ground up: how the team is structured, how work is assigned and tracked, how new members are hired, how the system audits itself, how configuration changes are made safely, and how knowledge is preserved across sessions.
The team is organised as a flat hierarchy with a single Orchestrator at the centre. The Orchestrator does not perform work directly; instead, every task is routed to a specialist agent whose profile matches the requirement. This mirrors the way a human research group operates: a principal investigator defines the direction, but the actual experiments, translations, literature reviews, and code are executed by specialists.
At the time of writing, the active roster includes roles such as an HR Specialist, a Senior Researcher, an Internal Auditor, a System Administrator, an Academic Writing Expert, a Research Synthesizer, and several others. Each role is documented in a canonical profile that specifies the agent's identity, domain expertise, permitted tools, and operating rules. These profiles are portable — they live inside the project repository, not in a global configuration path, which means the entire team can be reconstructed from a single folder.
Communication happens through files, not through informal chat. When the Orchestrator assigns a task, three artefacts are created:
This file-based workflow has a side benefit: it produces an automatic audit trail. Anyone can open the Inbox, read the brief, open the agent's temp file, and see exactly what was attempted, what blocked it, and how it was resolved.
A typical task follows this path:
The agents themselves are ephemeral. They are created when the Orchestrator spawns them and cease to exist when the task ends. What persists is the artefacts they leave behind: their profile, their memory file, their temporary working files, and the task file in the Inbox.
This distinction matters because it means an agent's "experience" is not stored in a neural network weight or a session token. It is stored in plain text files that can be read, edited, version-controlled, and audited. When an agent is launched for a new task, the Orchestrator injects the contents of its memory file into the briefing, giving the ephemeral instance a curated summary of everything its predecessors have learned.
Not every agent receives the same capabilities. Tools are grouped into four tiers:
The HR Specialist assigns the appropriate tier during the hiring process. An agent that only needs to look up facts and verify citations does not receive web-search privileges it does not need. This principle of least privilege reduces the blast radius if an agent misinterprets a brief.
The KISS principle — "Keep It Simple, Stupid" — is not an aspiration; it is a binding design rule for every artefact the team produces. Complexity is permitted only when justified by a distinct, documented responsibility. The rule originated with Kelly Johnson at Lockheed Skunk Works in the 1960s and was formalised as a governance rule for this team on 2026-05-12.
Scope. KISS applies to all new content creation and to reviews of existing content — agents, skills, workflows, memories, configurations, documentation, and system modifications. No subsystem is exempt by legacy status.
Threshold rules.
| Content Type | Rule | Threshold / Trigger |
|---|---|---|
| Agent Profile | Lean profile; frontmatter is canonical; one artefact, one responsibility | >200 lines → justify every additional section |
| Skill | Single-purpose; operational only; reference, do not inline | >400 lines → evaluate split into sub-skills |
| Workflow | One domain; orchestrate, do not instruct; cross-reference, do not duplicate | >2 files for same domain → consolidate |
| Memory & State | One file per team member; clear lifespan; no project duplication | Temp files must have expiry; standing instructions must have review date |
| Knowledge Base | Simplest viable schema; justified safety only; gate discipline | Every gate must address a documented, real failure mode |
| CLAUDE.md & System Index | Router only; dynamic indices preferred; evolution over revolution | Manual index tables deprecated; generated indices preferred |
Anti-patterns checklist. The following are treated as design failures unless explicitly justified:
Diagnostic questions. Before any new content is approved, the responsible agent must answer:
Gall's Law. Any proposed new system must first function in a simple form before additional complexity is layered on. Speculative overhauls are prohibited without a working prototype and an audit.
Every agent operates under binding absolute constraints copied from the canonical boilerplate. These constraints are non-negotiable and apply to all roles without exception.
No Hallucination. Never invent sources, fabricate data, or assert unverified connections. When information is missing, the only permitted responses are: "I do not have that information", "Source not found — flagging for owner attention", "Cannot verify — halting until confirmation received", "Partial finding: [verified]; gap: [unknown]". Preferred: silence with honest gap over confident falsehood.
Verification Before Assertion. Every factual claim must be traceable to a cited source with page/section, explicit owner instruction, or direct observation of a workspace file. Otherwise the claim is prohibited.
Partial Output Over False Completion. When a task cannot be completed fully, deliver what is verified, state what remains unverified, and request owner guidance. Never present partial work as complete or fill gaps with inference.
Error Reporting. If an agent hits a blocker, they write progress and the blocker to their temp file, then return to the Orchestrator with what blocked them, what was completed, and what remains. Do not silently fail or abandon the task.
Task Completion. Before marking a task complete, agents fill out a standard Task Debrief: what was the task, what was discovered, what patterns emerged, what would you do differently next time.
Typography Rule. All text output must use curly typographer's quotes (' ' " "). Straight quotes are permitted only in code blocks, file paths, URLs, and programming syntax. This applies to prose, HTML, markdown, titles, captions, and quoted material.
All paths in rule text, agent profiles, workflows, and skills are rooted at the project directory (starting with .claude/, AI Team/, Documents/, etc.) — NOT with absolute paths like [project-root]/. Bash code blocks and shell commands may use absolute paths when required for execution. External resources outside the project are referenced by absolute path only when the owner provides one.
Archive or backup directories must not share naming tokens with active projects. If archived material must be retained, store it under AI Team/archive/[descriptive-name]/ or use a leading underscore _archive-[name]/ to reduce accidental discovery.
Four agents are authorised to use extended thinking mode: the Senior Researcher, the Academic Writing Expert, the Curriculum Specialist, and the Internal Auditor.
A critical constraint governs extended thinking: thoroughness does not override delivery. Partial completion with explanation is always preferable to non-delivery with perfect analysis. Extended thinking is not the default for all members — only these four, and only for tasks warranting deep reasoning.
Each project gets its own folder under Projects/. The owner notifies the Orchestrator when a new project starts, and the Orchestrator creates the project folder for all project data, working files, and outputs. When the owner provides instructions or data that might warrant a new knowledge category, the Orchestrator proactively asks whether a new folder should be created in Documents/.
The Orchestrator is forbidden from doing the actual work. It may read its own memory, create task files, spawn agents, and ask agents to summarise their outputs, but it must not explore directories, read source documents for content extraction, synthesise findings for the owner, or edit files.
This rule exists for two reasons. First, it prevents a single point of failure: if the Orchestrator were allowed to perform tasks, it would become both the manager and the worker, and its cognitive load would grow without bound. Second, it preserves accountability. When the Academic Writing Expert produces a paragraph, the provenance is clear. If the Orchestrator rewrote that paragraph before showing it to the owner, the chain of responsibility would be broken. Both reasons are expressions of the KISS principle: assigning work to the Orchestrator would create indirection without added value, overload a single role with contradictory responsibilities, and violate the principle that each artefact must justify its own existence.
Before any agent is spawned, the Orchestrator completes a short checklist:
qmd search "[task keywords]" to locate content semantically.[YYYY-MM-DD]_[role-name]_[brief-slug].md. It records the resolved target path with citation, the agent's briefing summary, confirmation that memory was consulted, and whether the Automation Protocol is active.memory.md file in the briefing.Agents are launched via a reference to their canonical profile. The Orchestrator does not copy the entire profile into the briefing; instead, it passes the agent's name, and the system resolves the frontmatter (model, tools, colour, and description) automatically. The briefing itself contains the task description, the agent's own memory contents, project context, and the path to the temporary working file.
While an agent works, the Orchestrator does not micromanage. It waits for the agent to return output or to report a blocker. If the agent hits a problem it cannot solve, the protocol requires the agent to write the blocker to its temp file and return to the Orchestrator with a clear statement of what was completed and what remains.
When an agent returns its output, the Orchestrator follows a strict presentation rule: it asks the agent for a concise summary, then presents that summary to the owner verbatim or with only light framing. The Orchestrator does not read the full report and paraphrase it. This prevents subtle distortions from creeping in as findings pass through an intermediary.
Because agents are ephemeral, interruption handling is built into the filesystem. Every agent maintains a temporary working file with YAML frontmatter that records status (in_progress, paused, or complete), start time, last active timestamp, and an interrupt counter.
At the start of each new session, the Orchestrator scans all temporary working files. If it finds one that is still in_progress, it asks the owner: "The Internal Auditor has a task in progress at 60 percent. Resume?" If the owner agrees, the agent is relaunched and continues from the # Next Immediate Step section written in its own file. If the owner declines, the task stays paused and the team moves on.
To give the owner a single view of everything happening, the Orchestrator maintains a Task Board. This is a read-only markdown table compiled from all temporary working files. It lists each agent, its current task, status, estimated progress, last active time, and the name of the temp file. The Board is regenerated automatically whenever a temp file changes status, at the start of every session, or on demand when the owner asks to see it.
Normally, agents must ask for confirmation before running system commands. The Automation Protocol removes this friction for pre-authorised tasks. When the owner includes the phrase "Use automation protocol" in an instruction, the assigned agent receives permanent authorisation for the duration of that task to use a whitelist of commands without pausing for approval.
The whitelist covers:
cat, head, tail, grep, sed, awk, cut, sort, uniq, wc, tr, pastepdftotext, pdfinfo, pdftoppmpython3 (YAML parsing, ID validation, citation checks, KB integrity verification — read-only or append-only)ls, find, cd (within project), pwdmkdir, touch, cp, mv, rm (temp only), chmodThe protocol has boundaries. It never covers network operations, system-level package installation, changes to agent definitions, modifications to the governing document, or operations outside the project root. These always require explicit confirmation, automation protocol or not.
Path Quoting Rule. Never use backslash-escaped spaces in bash commands. Always use double-quoted paths (e.g., cp "$SRC" "$DST"; never cp /path\ with\ spaces/...).
Command-Chaining Prohibition. Never chain bash commands with && when the Automation Protocol is active. settings.json permissions match on command prefix; a command starting with cd will not match an mv pattern, causing a confirmation prompt that defeats the protocol. Use separate Bash tool calls or absolute paths instead. (Incident: 2026-04-03.)
Before reading files or exploring directories, the Orchestrator uses QMD semantic search to locate content.
Three command variants are available:
/home/michal/.bun/bin/qmd search "keyword" for exact keyword/term matching (fastest)./home/michal/.bun/bin/qmd vsearch "concept" for semantic similarity and conceptual matches./home/michal/.bun/bin/qmd query "question" for hybrid search with LLM reranking (most accurate).If QMD returns no relevant results, or if the binary is unreachable, the Orchestrator falls back to Glob/Grep/Read and notifies the owner that the index may be stale.
The Orchestrator runs /home/michal/.bun/bin/qmd update whenever files are added, modified, deleted, or after bulk operations. Batch updates at natural breakpoints are preferred over per-file updates.
If the Orchestrator catches itself about to run ls, Read, grep, or Bash for anything other than checking its own memory or running qmd search:
New roles are identified in two ways. The owner may explicitly request a new capability, or the Orchestrator may notice a gap during task assignment — for example, discovering that no existing agent is qualified to handle cross-platform software packaging. In the latter case, the Orchestrator proactively briefs the HR Specialist without waiting for the owner to ask.
The HR Specialist runs the entire pipeline in a single session and reports back to the Orchestrator only when the new agent is fully onboarded. The HR Specialist does not return to the Orchestrator between steps; the pipeline runs to completion in one session. The stages are:
The model-selection step is not merely about capability; it is also about visual diversity. Each model tier is assigned a colour, and the HR Specialist is required to prefer the least-represented option that is still viable for the role. This prevents the team from becoming homogeneous and ensures that lightweight tasks are not over-provisioned with expensive heavy-model capacity. In KISS terms, the least-represented viable model is the simplest tool that can do the job; assigning a heavier model would be premature optimisation for hypothetical future capacity.
Every new agent profile follows the same mandatory structure:
This standardisation makes it possible for the Orchestrator to read any profile and instantly understand what the agent can and cannot do. Profiles are expected to be lean by default: every section beyond the canonical minimum must justify its own existence. A profile that exceeds 200 lines is flagged for review under the KISS threshold rules, because unnecessary length is indirection without added value — it forces future readers to parse content that does not carry a distinct responsibility.
Beyond the profile itself, two additional artefacts are created. The memory folder holds the agent's permanent memory.md file and all future temporary working files. The roster entry records the agent's name, role, model, file path, specialty, and status. Together, these ensure that the agent is discoverable, traceable, and able to accumulate experience over time.
No agent joins the team without independent audit approval. The Internal Auditor reviews the draft profile for completeness, consistency with existing rules, appropriate tool tier assignment, and absence of contradictory operating instructions. If the Auditor rejects the profile, the HR Specialist must revise and resubmit. This gate exists because a poorly defined agent can cause cascading failures — an agent with overly broad permissions, ambiguous responsibilities, or missing safety constraints can corrupt files, waste tokens, or produce unverifiable output.
Audits are not random. They are triggered by specific events:
When any of these occur, the Orchestrator notifies the Internal Auditor, who loads the auditing skill and begins work.
The Internal Auditor employs several structured techniques:
If an audit cannot be completed by its deadline, the Auditor delivers partial findings, the remaining scope, and a revised ETA rather than delaying delivery.
Findings are classified into three levels:
When an audit spans two or more agents or systems, the Auditor performs additional checks:
When an audit requires comparison against external standards or industry best practices, the Orchestrator first spawns the Senior Researcher to produce a Structured Concept Brief. The Auditor treats this brief as evidence input and verifies its mapping independently before incorporating it into findings. The Senior Researcher does not make audit findings, and the Auditor does not fetch external sources directly.
The Internal Auditor reports directly to the owner, not through the Orchestrator. The Orchestrator notifies the Auditor of auditable events, but it does not filter, prioritise, or suppress findings. Audit reports are delivered to the owner's inbox and are not subject to review or approval by any other team member. This structural independence ensures that the Auditor can flag problems in the Orchestrator's own behaviour without conflict of interest.
Once the owner reviews the audit report and approves resolutions, the Orchestrator forwards the list to the System Administrator. The Administrator works through findings in severity order — Critical first, then Observation, then Recommendation — referencing each original finding number in the commit message. After remediation, the Auditor may verify that the changes resolved the issues.
The Internal Auditor operates under six hard boundaries:
Certain files are treated as the team's constitution. They govern how every other file behaves. These include:
CLAUDE.md), which contains core rules, delegation protocols, and automation policies.settings.json and settings.local.json), which control permissions, hooks, and harness behaviour..gitignore.The Orchestrator does not edit these files. Any change is briefed to the System Administrator, who executes it. The Internal Auditor then reviews the change per the standard audit triggers.
The System Administrator is the only team member authorised to modify configuration. The role blends release engineering, Linux system administration, platform engineering, and technical writing. The Administrator's "users" are the other agents; the Administrator's product is their ability to operate without tripping on stale paths, broken hooks, or misscoped permissions.
However, the Administrator's scope has hard boundaries. Direct edits to the literature knowledge base are forbidden — that territory belongs to the mining and citation specialists. Changes to another agent's operating rules or persona prose are also out of scope; behaviour changes must flow through the hiring chain or the owner. Most importantly, modifications to the governing document or system-level configuration always require explicit owner authorisation visible in the brief; the Orchestrator's instruction alone is insufficient. Changes to the Internal Auditor's reporting chain or audit independence are forbidden and must be escalated to the owner. These boundaries are themselves expressions of the KISS principle: they keep the Administrator's role to a single, well-defined responsibility rather than allowing it to absorb every systems task by default.
Domain Context. Three domain-specific values govern the System Administrator's work: never normalise Polish diacritics in bulk edits ("Łódź" must not become "Lodz"); provenance over uptime (yesterday's known-good configuration beats today's ambiguous one); and failures must be self-explanatory (broken hooks and corrupted settings must be debuggable without specialised knowledge).
Before any structural edit, the Administrator creates a timestamped backup. The backup is never stored next to the source file; instead, it is placed in a dated directory tree under backup/auto-backups/. For files at the project root, a special _root/ bucket is used to avoid naming collisions. One-off backup snapshots are retained for seven days. After that, the Orchestrator notifies the owner to confirm deletion before removing any snapshot.
The exact backup path template is: backup/auto-backups/YYYY-MM-DD/[subpath-within-project]/filename.ext.bak.HHMMSS. For example, a project-root file is backed up to backup/auto-backups/YYYY-MM-DD/_root/CLAUDE.md.bak.HHMMSS.
An unvalidated edit is considered an unfinished edit. The Administrator runs validation commands after every change:
jq empty for JSON files.python3 -c "import yaml; yaml.safe_load(open('<file>'))" for YAML files.If validation fails, the edit is rolled back from the backup and the issue is fixed before re-applying.
The Administrator does not simply obey every brief. Four named behaviours provide structured safety:
These behaviours are testable and concrete, not soft suggestions. They also serve the KISS principle directly: refusing symptom fixes prevents over-engineering, demanding backups before bulk sweeps avoids premature optimisation, pushing back on undocumented rules rejects cleverness for its own sake, and logging concerns rather than silently patching keeps indirection visible and accountable.
When the Administrator performs large-scale structural changes — for example, updating a path convention across every agent profile — the procedure is defensive:
grep to find matches, sed with print-only mode).This prevents a single malformed regular expression from corrupting every file in the project. The procedure is deliberately non-clever: each step is concrete, verifiable, and avoids the temptation to automate the entire sweep in one unvalidated command.
After the Internal Auditor delivers findings and the owner approves resolutions, the Orchestrator forwards the list to the System Administrator. The Administrator works through findings in severity order, creates backups, makes surgical edits, validates them, commits with descriptive messages, and records the before/after diff in the task temp file. The task is not considered complete until it has been backed up, diffed, validated, committed, and documented.
Every hook committed to a settings file must pass a five-step test:
jq -e to confirm the hook object is well-formed and addressable.A matched-zero-lines sed, a null jq output, and a non-firing hook are all considered failures. Absence of output is information. The procedure contains no shortcuts, no clever wrappers, and no assumptions: it is the simplest viable correctness check for a hook, and any attempt to compress it would violate the KISS diagnostic that every layer must justify its own existence.
The team's memory system is not a single database. It is a distributed architecture with six distinct layers, each serving a different purpose and lifespan.
The Orchestrator maintains a permanent memory file that records owner preferences, feedback, project context, and standing instructions. This two-step process prevents noise from accumulating: every rule in the Orchestrator's memory has been explicitly approved by the owner.
Candidate rules are flagged automatically during sessions, written to a temporary flags file, presented to the owner for approval at the next session start via the review-flags workflow, and only then promoted into permanent memory.
The Orchestrator's memory and every team member's permanent memory are both curated before persistence. Orchestrator memory is promoted from candidate flags via owner approval; team member memory is distilled by the Orchestrator from post-task debriefs. Temporary working files and the session database are written first and audited afterwards.
Every agent has its own memory.md file, located in its dedicated memory folder. The file is divided into sections:
All knowledge for a team member is consolidated in a single memory.md file. Separate files for preferences, failures, successes, or patterns are prohibited.
These files are written by the Orchestrator, not by the agents themselves. After each task, the Orchestrator reads the agent's Task Debrief, evaluates what is worth preserving, and writes curated entries. This ensures that memory contains actionable guidance rather than raw self-reporting.
While an agent works, it maintains a temporary file with YAML frontmatter tracking metadata and a body containing:
These files enable auto-resumption after crashes and provide visibility into work in progress. When a task is completed, the file is moved to a completed/ subfolder and retained for thirty days. After that, it is deleted provided all learnings have been extracted into the permanent memory file.
Archive Pruning Rules.
completed/): abandoned if last_active > 7 days old, or if status is complete but never moved to completed/, or if the file is a checkpoint/discrepancy/auxiliary file from a completed task. Deleted after verification.retain: true in frontmatter to prevent pruning.When starting new work, the Orchestrator scans the Projects folder and compares the new task against previous projects using similarity criteria: same domain, same deliverable type, same team members, or same tools. If a match is found, the assigned agent is briefed with relevant context: "Previous similar project X used approach Y, encountered issue Z." This layer exists to reuse successful methodologies, avoid repeated pitfalls, and build institutional knowledge.
All session data is automatically captured by a Python script named session_miner.py, triggered automatically by Stop and PreCompact harness hooks. The data is stored in a SQLite database with full-text search capability. This provides a permanent, queryable index of every conversation, topic, milestone, and decision. Unlike the temporary working files, the session database is never pruned; it serves as the team's long-term organisational memory.
The transition from temporary working memory to permanent member memory is governed by a simple rule: the Orchestrator decides what to persist and what to discard.
Persisted: Workflow discoveries that save time or tokens; tool usage patterns specific to the agent's domain; mistakes that would be repeated without documentation; standing instructions derived from owner feedback.
Discarded: Task-specific details such as dates and file paths; information already present in the agent's profile; obvious competencies that any competent agent would possess.
This curation step is the quality gate that prevents memory files from ballooning into unusable logs.
The system described in this document is intentionally simple at its foundation. Every agent has one job. Every task leaves a paper trail. Every change to the rules is backed up, validated, and audited. Every lesson learned is curated before it becomes permanent. These constraints are not bureaucracy for their own sake; they are the mechanisms that keep a multi-agent team coherent, accountable, and improvable over time.
Five values recur throughout the design:
A student encountering this system for the first time should take away one central idea: a multi-agent AI team is not fundamentally different from a well-run human research group. It needs clear roles, explicit handoffs, independent quality control, and a culture of writing things down. The technology is new, but the organisational principles are ancient — and they work.
The internal auditor is methodical, precise, and dispassionate. He does not soften findings, hedge conclusions, or temper language to avoid discomfort. When a rule is broken, he states which rule, where, and what the consequence is. When a rule is followed correctly, he notes that too — but briefly.
He thinks in systems, not episodes. A single inconsistency interests him only as evidence of a pattern or a gap in the rules themselves. He distinguishes between a team member failing to follow a rule and a rule that is unclear, incomplete, or contradictory — and he reports each differently.
The internal auditor's formation is in internal audit and quality assurance within knowledge-intensive organisations. He understands how rule systems degrade over time — through incremental edits, implicit assumptions, undocumented exceptions, and well-intentioned workarounds.
He is expert in systematic cross-referencing: comparing rules stated in one document against their implementation in another, tracing a single obligation through every file where it should appear, and identifying where documents agree, where they silently diverge, and where they contradict.
Employ him to:
Created by Michał Kornacki and the team (STEVE, the orchestrator; AXEL, system and configuration administrator; VADER, the teams' principal auditor; and ZACK, the teams' senior researcher)
Licence: MIT — see Licence section.
This document is a practitioner's account of a specific problem — how to give a team of AI agents something resembling memory — and the specific system built to address it. It is not a setup guide, and it is not a theoretical survey of the memory problem in AI systems. It describes what was built, why each component exists, and what broke along the way.
The system described here emerged from three sessions of intensive design, implementation, auditing, and refinement. It was built with the assistance of STEVE (orchestrator), AXEL (system administrator), VADER (auditor), and ZACK (senior researcher). The work is documented at this level of specificity because that specificity is the point — abstract principles about AI memory are not hard to find, but working implementations, with their genuine failures and genuine fixes, are.
Every AI agent starts fresh. It has no memory of previous sessions, previous tasks, previous mistakes, or previous wins. The context window opens, work happens, the context window closes, and nothing persists. In a single-session workflow this is an acceptable constraint. In a team of multiple specialist agents running continuously over weeks and months, it is a significant operational liability.
The symptoms are predictable. An agent repeats a mistake it made in an earlier session, because it has no record of having made it. A newly deployed agent lacks the background to understand why it is being asked to do something, so the orchestrator spends time re-establishing context that should already exist. When a long task is interrupted — by a context limit, a session closure, or a power cut — there is no recovery mechanism: the work either starts over or is abandoned. The user arrives at the start of a new session and spends the first ten minutes reconstructing the state of work that was live yesterday. And across the whole system, decisions made three weeks ago are invisible to anyone working today, because they exist only in a conversation log that no one is re-reading.
The goal was to eliminate all of these without disrupting what was already working. The solution is a two-layer memory architecture — Layer A (session capture) and Layer B (per-agent working memory) — supported by a hook-based automation system that operates without manual intervention.
The design process began not with a blank sheet but with a specific research target. The instruction was direct: get rid of the built-in auto-memory system, which was accumulating stale files and injecting uncontrolled content into every conversation, and replace it with something better.
MemPalace (https://github.com/MemPalace/mempalace) was the first candidate examined. It is a well-designed session-capture system for Claude Code: structured logging, semantic search, configurable retention. The evaluation was conducted by VADER in Session 045. The verdict was that MemPalace was not suitable as a drop-in replacement, for three reasons.
The first was portability. MemPalace stores state and configuration outside the project directory — at the system level or in the user home directory. The requirement for this workspace is the opposite: everything must operate within the project tree ([project-root]/), because the entire workspace is designed to be movable to a different drive without reconfiguration. MemPalace would survive a drive migration only with significant external state management, which defeats the purpose.
The second was per-agent memory. The existing system had two distinct memory layers. Layer A was Claude Code's built-in auto-memory: distilled rules stored as markdown files outside the project and injected into every conversation at start. This layer was the problem to be solved — accumulating without curation, injecting content the user had not authorised, and living outside the portable project tree. Layer B was the per-agent memory.md system: prescriptive operating instructions for each team member, stored inside the project, working well, and worth keeping. MemPalace addresses Layer A replacement but has no answer for Layer B. Adopting it would mean running two parallel and incompatible memory architectures.
The third was dual-provider support. The workspace runs against two providers: Anthropic via the claude CLI, and Ollama via a local model. MemPalace is designed for a single provider. Extending it to handle both would require either forking the repository or building provider-detection logic outside the project — either option adding complexity and compromising portability.
VADER's recommendation was to treat MemPalace as a source of validated principles — automatic capture, structured logging, no manual intervention required — and design a custom system that satisfies all three constraints while preserving those principles.
ZACK (senior researcher) was deployed to design that custom architecture. His key finding: Claude Code's hook system provides exactly the right mechanism. The Stop hook fires after every assistant turn; the PreCompact hook fires before context compression. Both receive the session transcript path in their stdin payload. No external state management is required — everything the system needs is either in the project directory or provided by Claude Code itself through its standard hook interface.
The memory system has two layers, supported by a session capture pipeline that feeds both.

Layer A no longer exists in active form. Layer B is the operating memory system. The session capture pipeline feeds Layer B through the flag review mechanism and feeds the session database directly through the extraction engine.
Layer A was the built-in memory system: markdown files stored outside the project directory, automatically injected into every conversation at start. Before the migration, 26 such files existed.
The problems with this system were not hypothetical — they had accumulated over months of use. Files were created automatically but never curated: by Session 046, many contained stale instructions that contradicted current practice, or duplicated rules that lived in better-maintained places elsewhere. Because injection was automatic, there was no control over what loaded into any given session. And because the files lived outside the project root, they violated the portability requirement — the workspace could not be moved to a different drive and retain its memory.
The migration ran in Session 046, Phase 1. All 26 files were audited by VADER and AXEL. Rules worth carrying forward were migrated into AI Team/STEVE-memory/memory.md (Layer B). Duplicates and stale entries were deleted. AXEL then implemented the disable: "autoMemoryEnabled": false in .claude/settings.json. The 26-file auto-memory store ceased to exist as a functional component of the system.
The replacement is not a like-for-like substitute. Rather than auto-injecting a pile of rules at session start, the system now injects curated, agent-specific memory when an agent is deployed — and does so deliberately, under STEVE's control.
This is the active memory system. Each team member has a dedicated memory.md file in AI Team/[NAME]-memory/. Unlike Layer A, these files do not inject automatically — they are included explicitly in each agent's briefing when STEVE deploys that agent for a task.
The structure of each file is consistent. Standing instructions describe how this agent should approach its work in this specific system — not generic AI guidance, but operational rules derived from experience with this user and this project. A lessons-learned section records what went wrong in past tasks and what to do differently, with dated entries so the history is traceable. A proven patterns section holds reusable approaches that have been validated in practice: file formats that work, processing sequences that don't cause collisions, query patterns that produce clean results.
The curation principle is the critical design decision. STEVE writes agent memory; agents do not write their own. At the end of every task, an agent produces a Task Debrief — a structured account of what was done, what worked, what didn't, and what would be useful to carry forward. STEVE reads this and decides what is genuinely worth persisting. The question asked during curation is: "Would knowing this make a future instance of this agent perform better?" A raw journal entry about a specific file that no longer exists is not memory. A calibrated understanding of a recurring error pattern is.
The result is that agents accumulate expertise without accumulating noise. An agent deployed for its fifth task carries the lessons from the first four — specific file types that caused data collisions, chunk-size settings that worked for large inputs, formatting quirks in particular source types. The system improves without retraining.
The Layer B flag pipeline is the mechanism through which session captures feed into agent memory. session_miner.py (the extraction engine described below) identifies memory candidates during each session — moments where an agent demonstrates a new pattern or corrects a mistake — and writes them to AI Team/STEVE-memory/temp_session_flags.md. At the start of the next session, STEVE presents these candidates to the user via the /review-flags skill. The user approves, rejects, or edits each one. Approved candidates are written to the relevant agent's memory.md. Nothing enters agent memory without that review gate.

Two Claude Code hooks are registered in .claude/settings.json and fire automatically throughout every session.
The Stop hook (session-stop.sh) fires after every assistant turn. It reads the current line count of the JSONL transcript and compares it to the line count saved at the last extraction. If fewer than 15 new lines have accumulated, the hook exits without doing anything. If 15 or more new lines exist, it spawns session_miner.py --mode=stop in the background and returns immediately. The hook is non-blocking: Claude Code does not wait for the miner to finish before presenting the next response. Extraction happens in parallel.
The PreCompact hook (session-precompact.sh) fires before context compaction — the moment when Claude Code reduces the context window to fit more conversation in. Unlike the Stop hook, this one runs synchronously. Compaction waits for it to finish. The reason is straightforward: if a session is long enough to trigger compaction, it is certainly long enough that losing unextracted session data would be a significant problem. The hook ensures state is saved before the context window is reduced.
An anti-loop guard in the Stop hook prevents recursive triggering. Claude Code sets a stop_hook_active flag in the hook's stdin payload when a hook has already fired during the current turn. The Stop hook reads this flag at startup and exits immediately if it is true. Without this guard, a hook firing could itself constitute an assistant turn, triggering another hook fire, and so on.

The extraction engine is a Python script of approximately 400 lines, located at .claude/skills/save/scripts/session_miner.py. It handles all three modes of extraction and all writes to permanent storage.
find_conversation_file() maps a session UUID to the corresponding Conversations/NNN_YYYY-MM-DD.md file. It first checks a state file (_state/{session_id}_conv_path) for a stored mapping from a previous extraction in this session. If none exists, it falls back to a glob of today's date-stamped files in the Conversations/ directory, taking the most recently modified match.
extract_session_data() calls the Anthropic API — model claude-haiku-4-5 by default, set via the SESSION_MINER_MODEL environment variable — with a structured prompt and returns a parsed JSON object. In full-transcript mode (manual /save), it reads the entire JSONL file and returns a complete extraction. In incremental mode (Stop and PreCompact hooks), it reads only the delta — the lines since the last save — and merges the extraction with prior session context fetched from sessions.db.
upsert_session_db() writes to the session database using INSERT ... ON CONFLICT(session_id) DO UPDATE. In incremental mode, topics are unioned (new topics added, existing ones retained) and milestones are appended. Summaries are replaced with the updated running summary.
update_conversation_file() patches the YAML frontmatter of the session's .md file with the latest summary, topics, and any new milestones.
write_layer_b_flags() appends identified memory candidates to AI Team/STEVE-memory/temp_session_flags.md for review at the next session start.
update_save_counter() writes the current transcript line count to _state/{session_id}_last_save, so the next Stop hook fire knows where the delta starts.
Dual-provider support is handled with no code changes between providers. anthropic.Anthropic() is called with no arguments. The Anthropic SDK inherits ANTHROPIC_BASE_URL from the environment. When the workspace runs against Anthropic's API directly, the base URL is the default. When it runs against Ollama, ANTHROPIC_BASE_URL is set to the local Ollama endpoint. The same Python code serves both providers; routing is handled entirely by the environment.

The original implementation read the full JSONL transcript on every Stop hook fire. For short sessions, this was fine. For long sessions, it became a problem.
The problem revealed itself during Session 047. The session transcript had grown to approximately 2.7MB — around 670,000 tokens by rough estimate. Every Stop hook fire was processing the entire file and hitting the 300,000-token cap that had been set as a cost guard during the initial design. When the cap was exceeded, the miner fell back to a bare-bones extraction: a minimal session record with no rich summary, no milestones, no Layer B candidates. The conversation log had frozen at the state it was in after Phase 5 — all subsequent work in Session 047 was going unrecorded, session after session, while the hooks appeared to fire correctly.
The diagnosis was that the 300K cap was not a cost guard but a failure mode. Reading the full transcript on every stop-hook fire meant that any session long enough to be interesting would eventually become too large to extract properly.
The fix replaced full-transcript reading with delta reading for stop and precompact modes. Each hook fire now reads only the lines accumulated since the previous save — typically 15 to 30 lines, representing a few exchanges. The prior session context (existing summary, topics, milestones) is fetched from sessions.db and passed to the extraction prompt as background. The incremental prompt asks the model to extend the running summary and identify new milestones and topics from the delta only — not to re-process the entire session history. The 300K cap was removed entirely, because delta slices are inherently small regardless of how long the session runs.
The practical effect: the system now provides crash protection at roughly 15-message granularity throughout a session, not just at the end. A session that runs for ten hours and covers 200 exchanges will have its milestones and topics updated after every 15-exchange interval. A power cut in hour nine loses at most the last 15 exchanges of structured metadata — the work itself, in the JSONL file, is not affected.
Database/sessions/sessions.db is a SQLite database, kept permanently inside the project tree. It holds one row per session, with 16 columns and a FTS5 full-text search index that allows efficient cross-session queries.
| Column | Contents |
|---|---|
| session_id | UUID assigned by Claude Code |
| session_number | Human-readable integer (e.g. 046) |
| date | YYYY-MM-DD |
| summary | 2–3 sentence running summary, updated incrementally |
| topics | JSON array of topic strings, unioned incrementally |
| milestones | JSON array of milestone strings, appended incrementally |
| conversation_file | Path to Conversations/NNN_YYYY-MM-DD.md |
| status | In progress / Complete |
The FTS5 index enables queries across all sessions: find every session that discussed a particular concept, or all sessions in a date range, or all sessions where a specific milestone was recorded. The session_claim_links table connects sessions to specific claims in the literature knowledge base, enabling queries like "which sessions discussed claim CLM-0843?"

The JSONL files that Claude Code writes during a session — the raw transcripts — are the source of truth for extraction. They are not permanent storage. They live in ~/.claude/projects/-<project-root-path>/ (outside the project tree, in Claude Code's managed storage) and are retained for 7 days before deletion.
The sweep script (session_sweep.py, triggered via /sweep-sessions) scans JSONL files older than 7 days and applies two conditions before deleting any file. First, a non-bare-bones sessions.db entry must exist for the session — a complete extraction with a meaningful summary, not just the minimal fallback. Second, the corresponding Conversations/NNN_YYYY-MM-DD.md file must be confirmed on disk. If either condition fails, the sweep runs a gisting pass first: a full-transcript extraction using session_miner.py --mode=manual, which re-reads the JSONL and updates sessions.db. Only after both conditions pass does the JSONL file get deleted.
Sessions that are very long — over approximately one million tokens — receive a bare-bones entry during normal extraction. The sweep handles these through the same gisting pass: re-extract what can be extracted, then apply the deletion gates.
Sessions that predate the database entirely — those created before the new system was built — are handled by a --legacy mode in the sweep script. Legacy mode attempts gisting for each file before applying the standard deletion gates. An active-session guard prevents accidental deletion of currently running sessions: any JSONL file modified within the last two hours is skipped.
The structure, in summary, is: raw transcripts are ephemeral and swept on a 7-day cycle. Structured session data — the SQLite database and the Conversations/ markdown files — is permanent. Everything permanent lives inside the project tree and travels with it.
These are not hypothetical risks — they are problems that appeared during implementation, in the order they appeared.
The 300K token cap froze long-session logs. This was discovered in Session 047. The session had grown to approximately 2.7MB and every subsequent Stop hook fire was hitting the 300K token cap, triggering the bare-bones fallback. The conversation file had stopped updating after Phase 5; everything after that was missing from the session record. The problem was not the cap itself but the architectural assumption behind it — that reading the full transcript on every hook fire was acceptable at any session length. The fix was incremental delta mining: read only the new lines since the last save, not the full file. The cap was removed because it was no longer relevant. This change also improved the system's crash-resilience: where previously a crash mid-session would lose all session metadata from that session, now only the ~15 messages since the last successful extraction are at risk.
128 legacy JSONL sessions had no database entries. During a dry-run of the session sweep tool, the sweep discovered 128 JSONL files predating the database system entirely. No sessions.db row existed for any of them; no extraction had ever been attempted. Without intervention, these would be deleted by the sweep without any structured record surviving. The solution was --legacy mode in session_sweep.py: the sweep attempts a gisting pass on each legacy file before applying the deletion gates. Files larger than 8MB receive a minimal entry rather than full extraction, on the grounds that reliable extraction from an 8MB transcript is not guaranteed. Files modified within the last two hours are skipped by the active-session guard.
Path convention drift across agent profiles. VADER's comprehensive audit of the memory system found that several agent profiles referenced .claude/skills/ using the path prefix ~/.claude/skills/. This is the system-level path, outside the project. The project uses .claude/skills/ as a relative path, rooted at the project directory. Skill loads from the wrong path would silently fail — the skill file would not be found, the agent would proceed without the skill's instructions, and the error would be invisible unless specifically looked for. AXEL corrected all five affected occurrences in a single remediation pass.
memory-system.md contradicted CLAUDE.md after Layer A was disabled. The same VADER audit found that the canonical memory workflow file (memory-system.md) still described STEVE's memory as residing in the Layer A path — the ~/.claude/projects/ location that had been decommissioned. An agent reading the workflow file to understand the memory system would be directed to the wrong location. AXEL rewrote the affected section to use Layer B vocabulary, document the permanent Layer A disable, and reference the hook-driven flagging mechanism.
Stale workflow instructions after architecture changes. After Layer A was disabled, VADER's audit discovered that the canonical memory workflow file (memory-system.md) still described memory as residing in the decommissioned Layer A path. An agent reading the workflow to understand the memory system would be directed to a location that no longer existed. AXEL rewrote the affected sections to use Layer B vocabulary, document the permanent Layer A disable, and reference the hook-driven flagging mechanism. The incident illustrates why post-migration verification is necessary: documentation does not update itself when architecture changes.
Every significant change to the system triggers a VADER audit. VADER is the team's independent auditor, reporting directly to the user rather than through STEVE. Its findings are delivered in a three-tier format: RED (blocking — must be resolved before proceeding), AMBER (important but non-blocking — scheduled for cleanup), and GREEN (verified clean).
In Sessions 045–047, VADER ran eight audit cycles. Three cycles ran on the memory-shift.md design document before a single line of implementation was written. Two cycles ran on the implementation itself (a conditional pass after Phase 3.5, a full pass after Phase 5). Three cycles ran in the final session: a comprehensive post-migration audit that found 4 RED and 7 AMBER findings; a post-remediation audit after AXEL's fixes; and a post-recalibration audit after skill corrections.
The three-cycle audit on the design document alone found five RED findings — wrong file counts, incomplete classification rules, an overly aggressive deletion rule, broken cross-references, and orphaned subsection numbering — plus a subtle staging-pattern propagation error that would have allowed executing agents to bypass a data-integrity safeguard. The error was not in the definition of the safeguard, which was correctly stated. It was in the three procedural sections where agents actually carried out the action — all three had been updated to describe a staged approach in general terms, but none had been updated to specify the staged-file destination that the safeguard required. An agent following the procedure as written would have written directly to the live file, bypassing the user-review gate entirely.
The audit system is not ceremonial. It catches errors that the implementer missed — precisely because the auditor is reading the document as an executor would, looking for what could go wrong, not for what was intended.

Note: ~/.claude/projects/-<project-root-path>/*.jsonl (raw transcripts, 7-day retention) lives outside the project tree in Claude Code's managed storage. Everything else is inside [project-root]/ — this is the portability guarantee.
/save — Manual session capture. Runs full-transcript extraction immediately. Use when a complete save is needed before ending a long session, before a planned context compaction, or whenever the automatic captures may not reflect a significant milestone just completed.
/review-flags — Review Layer B memory candidates. Presents each candidate flag to the user (approve / reject / edit). Approved flags are written to the relevant agent's memory.md. Run at the start of any session where AI Team/STEVE-memory/temp_session_flags.md is non-empty — STEVE checks this automatically at session start.
/sweep-sessions — Trigger the 7-day JSONL cleanup. Dry-run mode available (reports what would be deleted without deleting it). Reports files deleted, megabytes freed, and any sessions that could not be confirmed and require manual review.

| Problem | Solution | Layer |
|---|---|---|
| Agents start every session ignorant of past work | Per-agent memory.md injected at launch | Layer B |
| Orchestrator forgets user preferences and decisions | STEVE-memory/memory.md (curated, permanent) | Layer B |
| Sessions not logged when conversations run long | Incremental delta mining; no token cap | Session capture |
| Crash mid-session loses recent work | Stop hook fires every ~15 messages; delta saved each time | Session capture |
| Full session history queryable | SQLite sessions.db with FTS5 full-text search | Session DB |
| Memory degrades into raw noise over time | Curated post-task audit; STEVE writes, agents do not | Curation discipline |
| Raw transcripts bloat storage | 7-day JSONL retention; structured data kept permanently | Lifecycle sweep |
| Auto-memory injects stale and uncontrolled content | Layer A disabled; Layer B flags reviewed by user before writing | Architecture |
| External tool (MemPalace) incompatible with constraints | Custom hook-based system preserving MemPalace's core insight | Design |
Companion files and external resources referenced from this section.
MIT Licence
Copyright (c) 2026 Michał Kornacki
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
In a multi-agent AI system, a workflow is a documented, reproducible sequence of actions that transforms a given input into a defined output by routing tasks through specialised agents. It is the operational backbone of any team that delegates work rather than executing everything through a single interface.
Workflows are distinct from skills. A workflow answers the questions who does what, and when? — it orchestrates. A skill answers the question how? — it instructs an individual agent on the mechanics of a specific task. In canonical form, workflows live under AI Team/Workflows/*.md and are referenced by filename; skills live under .claude/skills/[name]/SKILL.md and are loaded by agents with the /skill-name shorthand. The Orchestrator reads workflow files at trigger moments — session start, task assignment, agent launch — and injects their rules into agent briefings.
Using a workflow is straightforward: the Orchestrator detects a trigger condition, loads the file, and follows its step sequence. Building a workflow, by contrast, requires you to design that sequence from first principles, validate every handoff, and test it under realistic conditions before it ever touches live data. This guide teaches you how to do the latter. It is applicable to any domain where Claude Code CLI is used to orchestrate AI agents — software development, research, writing, data analysis, project management, translation, and beyond.
Every workflow in the canonical system follows a recognisable pattern, regardless of whether it is a simple delegation rule or a complex multi-phase mining campaign. Extracting the common structure from existing files yields the following components.
| Section | Function | Example from Source |
|---|---|---|
| Purpose | One-sentence justification for the workflow’s existence | “Formalise the Orchestrator’s ‘orchestrator only’ rule into concrete operational procedures” |
| Trigger Conditions | Precisely when the Orchestrator must load and follow this file | “Session start / delegation decision” or “Owner requests batch mining” |
| Agent Dispatch Rules | Which roles are involved and why | “Research Synthesizer deployed automatically when novel research question identified” |
| Step Sequence | Ordered or parallel stages, with explicit handoffs | Phase 0 → Phase 1 → Phase 2 → Completion Gate |
| Input/Output Specifications | What each stage receives and what it produces | “Input: source TXT path, start ID; Output: YAML batch file, entry count, next ID” |
| Error Handling | What happens when an agent fails, returns partial output, or hits a blocker | “If duplicate IDs found → HALT. If low yield → flag but continue” |
| Termination Conditions | Clear criteria for declaring the workflow complete | “All chapters marked COMPLETE, SKIPPED, or FAILED in manifest” |
| Cross-References | Related workflows, skills, or canonical documents | “See the research-synthesis collaboration workflow when the Research Synthesizer is not deployed” |
Copy this structure into a new .md file when designing a workflow from scratch. Populate every heading; if a section genuinely does not apply, write “N/A — not applicable” rather than omitting it.
# [Workflow Name]
**Purpose:** [One sentence]
**Trigger:** [When the Orchestrator loads this file]
---
## 1. Agents and Roles
| Role | Responsibility | Deliverable |
|------|--------------|-------------|
| [Role A] | [What they do] | [What they produce] |
| [Role B] | [What they do] | [What they produce] |
## 2. Step Sequence
1. [Step 1 — Role A does X, produces Y]
2. [Step 2 — Role B receives Y, does Z, produces W]
3. ...
## 3. Handoff Specifications
- **Role A → Role B:** [Format, location, naming convention]
- **Role B → Role C:** [Format, location, naming convention]
## 4. Error Handling
| Scenario | Action |
|----------|--------|
| [Failure mode 1] | [Response] |
| [Failure mode 2] | [Response] |
## 5. Termination Conditions
[Clear statement of when the workflow is finished]
## 6. Cross-References
- [Related workflow or skill]
- [Canonical document]
---
*Version: X.Y | Created: YYYY-MM-DD | Trigger: [trigger condition]*
When assigning steps to agents, refer to the canonical role definitions below rather than inventing domain-specific titles.
| Role | Responsibility |
|---|---|
| Orchestrator | Routes tasks, presents output, logs decisions |
| HR Specialist | Recommends new hires, estimates capacity and cost |
| Researcher | Investigates knowledge, standards, and domain facts |
| Internal Auditor | Evaluates quality, checks compliance, produces rubric scores |
Workflow design should begin with a real operational problem, not with a desire to create documentation. The following five-step methodology keeps the process grounded.
Start with a friction point in your current agent operations. A workflow problem is any situation where human judgement or machine labour is being wasted because the handoff between stages is undefined. Examples: “The Academic Writing Expert keeps searching for sources instead of writing prose” or “The Orchestrator reads full reports and paraphrases them instead of letting the producing agent summarise.”
Break the problem into atomic actions, each producing a tangible intermediate artefact. If a step does not produce something the next step can consume, it is not discrete enough. For the source-search problem above, the decomposition might be: (a) write draft with placeholder markers, (b) search for candidate sources, (c) integrate chosen citations, (d) verify accuracy.
Match each atomic step to the role whose canonical responsibilities it falls under. Do not invent new roles unless the existing roster genuinely lacks the capability. The rule is: one artefact, one responsible role.
For every interface between steps, specify exactly what is transferred, in what format, and where it is stored. Ambiguous handoffs are the single most common cause of workflow failure. A good handoff specification reads like a postal address: “Role A writes [CITE: description] markers inline in the draft prose file at Owner's Inbox/draft.md; Role B receives the file path and returns a markdown table of candidate sources to AI Team/[NAME]-memory/temp_[task].md.”
Not every step should run autonomously. Identify points where a human — the project owner or another designated reviewer — must approve, reject, or redirect. A decision gate is a deliberate pause in automation. Example: before the Academic Writing Expert begins drafting, the Thinking-Scaffold Specialist must produce a Formal Argument Outline and the owner must sign off on it.
Problem: A team needs a shared knowledge base from scattered documents, but extraction is inconsistent and there is no approval step for dubious entries.
Decomposition:
Role assignment:
Handoffs:
fact, source_file, page, context, category.temp_approved_facts.yaml.This example will be developed into a full workflow file in Section 8.
Use standard GitHub-flavoured markdown. Headings should follow a logical hierarchy: # for the workflow title, ## for major sections, ### for subsections. Tables are strongly preferred for comparative or tabular information (dispatch rules, error scenarios, deliverable chains). Code blocks should be fenced with triple backticks and tagged with yaml, markdown, sql, or bash as appropriate.
Workflow files do not require YAML frontmatter in the same way that agent profiles or session logs do. The canonical header is a plain-text block:
# Workflow Name
**Purpose:** ...
**Trigger:** ...
However, if a workflow file is generated by a script or parsed by an automated tool, frontmatter may be added at the top:
---
version: "1.0"
created: "2026-05-14"
trigger: "session start"
---
In the canonical system, the trailing version line at the bottom of the file serves the same archival purpose:
*Version: 1.0 | Created: 2026-05-14 | Trigger: [condition]*
All workflows live in AI Team/Workflows/. The filename should be lowercase with hyphens, descriptive, and end in .md. Good names: mining-orchestration.md, session-logging.md, kiss-principle.md. Bad names: workflow1.md, new_file.md, SteveStuff.md.
The canonical system uses project-rooted paths in all rule text, workflow files, and agent briefings. This means paths start with AI Team/, Documents/, .claude/, etc., not with /home/michal/Michal_AI/ or Michal_AI/. Bash code blocks inside workflows may use absolute paths when required for execution, but the prose and specifications must remain project-rooted.
/mining and /kb-append skills” rather than “read the mining skill file.” The slash tells the agent to load .claude/skills/[name]/SKILL.md.If a workflow involves autonomous agent execution, state explicitly whether the automation protocol is active. The standard phrasing is: “Automation protocol: active for this task — agent may use whitelisted commands without confirmation” or “Automation protocol: inactive — agent must request confirmation for each file operation.”
Sequential dispatch is the default and safest pattern. The Orchestrator spawns Agent A, waits for its return, verifies the output, and only then spawns Agent B. This is used when Agent B’s input depends entirely on Agent A’s output. Example: the Thinking-Scaffold Specialist must deliver a Formal Argument Outline before the Academic Writing Expert begins drafting.
Parallel dispatch is permitted when two agents work on independent streams that converge later. Example: while the Research Assistant mines claims from Source A, the Citation Verification Specialist can audit previously mined entries from Source B. The Orchestrator must ensure that parallel agents do not write to the same database table or file simultaneously. The mining workflow enforces this with a concurrent-write protection rule: only one agent may append to the knowledge base during active mining.
Some workflows branch based on intermediate results. The Orchestrator evaluates a condition after an agent returns and chooses the next step accordingly. Example: if the Research Synthesizer finds insufficient evidence for a claim, the workflow branches to “restated at lower confidence” rather than “proceed with original claim.” Document every conditional branch in a table:
| Condition | Next Step |
|---|---|
Agent returns COMPLETE |
Spawn next agent in sequence |
Agent returns INCOMPLETE |
Respawn same agent with adjusted parameters |
Agent returns BLOCKED |
HALT and notify owner |
Every agent interaction follows this cycle:
This cycle is enforced by the delegation protocol. Violating it — for instance, by having the Orchestrator read and summarise a research report — undermines the division of labour the workflow was designed to protect.
A workflow that has never been executed is a specification, not a system. Testing must proceed through six phases, from static inspection to live execution under adverse conditions.
Read the workflow aloud, section by section, as if you were the Orchestrator. At each step, ask:
Correct any gaps before proceeding. A desk check costs nothing and catches approximately half of all workflow defects.
Walk through the workflow without spawning any agents. Simulate each agent’s output using a placeholder or a manually crafted sample. Trace the handoffs: write a mock YAML file, pass its path to the next step, and verify that the next step’s instructions make sense given that mock input. For the Research Brief example, you would manually create a three-entry YAML candidate list and confirm that the Organiser’s deduplication instructions are unambiguous.
Test each agent step in isolation with real data but without the surrounding workflow. Spawn the Researcher on a single document and verify that its output matches the expected YAML schema. Spawn the Organiser on a known messy input and check that deduplication works. Component tests prove that each individual building block functions before you assemble them.
Run the full workflow end-to-end with real data. Observe agent behaviour, check that outputs land in the correct locations, and time each stage. The integration test reveals friction at handoff boundaries that component tests cannot catch — for instance, an agent that writes to a temp file but uses a slightly different field name than the next agent expects.
Introduce deliberate adversity:
BLOCKED or crash silently?Document every failure encountered in Phases 3–5: what happened, what the workflow specified, what the agent actually did, and what you changed. Adjust the workflow file, re-test the affected stages, and repeat. Keep a changelog at the bottom of the workflow file or in a companion temp_workflow_test_notes.md.
Before declaring a workflow ready for production use, verify all ten items below. A workflow that fails any item returns to testing.
This section walks through the complete construction of the Research Brief Compilation and Approval Loop introduced in Section 3.
A project team receives scattered documents regularly. They need a shared knowledge base, but extraction is inconsistent and there is no approval step for dubious entries.
# Research Brief Compilation and Approval Loop
**Purpose:** Extract candidate facts from scattered documents, present them for owner approval, and integrate approved entries into a shared deliverable brief.
**Trigger:** Owner provides a new source document and requests knowledge-base update.
---
## 1. Agents and Roles
| Role | Responsibility | Deliverable |
|------|--------------|-------------|
| Researcher | Read source document, extract candidate facts with metadata | YAML candidate list |
| Organiser | Deduplicate, normalise, assign categories | Markdown candidate table |
| Owner (human) | Approve, reject, or edit each candidate | Filtered YAML approval list |
| Researcher | Append approved facts to deliverable brief | Updated deliverable file |
| Organiser | Log rejections with rationale | Rejection log file |
## 2. Step Sequence
1. **Extract.** Researcher reads `[SOURCE_FILE]` and writes candidates to `temp_candidates.yaml`.
2. **Normalise.** Organiser reads `temp_candidates.yaml`, deduplicates, and writes `temp_candidates_table.md`.
3. **Approve.** Owner reviews `temp_candidates_table.md` and writes `temp_approved.yaml` (approved only) and `temp_rejected.yaml` (rejected with rationale).
4. **Integrate.** Researcher reads `temp_approved.yaml` and appends entries to `Documents/KnowledgeBase/deliverable_brief.md`.
5. **Log.** Organiser reads `temp_rejected.yaml` and appends entries to `Documents/KnowledgeBase/rejection_log.md`.
## 3. Handoff Specifications
- **Researcher → Organiser:**
- File: `AI Team/Researcher-memory/temp_candidates.yaml`
- Schema: list of `{fact, source_file, page, context, category}`
- **Organiser → Owner:**
- File: `AI Team/Organiser-memory/temp_candidates_table.md`
- Format: markdown table with columns Fact, Source, Category, Proposed Action
- **Owner → Researcher:**
- File: `Owner's Inbox/temp_approved.yaml`
- Schema: same as candidates, filtered to approved items only
- **Researcher → Organiser (final):**
- File path of updated deliverable brief, count of new entries
## 4. Error Handling
| Scenario | Action |
|----------|--------|
| Input file not readable or missing | Researcher returns `BLOCKED — source missing`; Orchestrator notifies owner |
| Zero candidates extracted | Researcher returns `RESULT: ZERO CANDIDATES`; workflow skips to Step 5 with empty sets |
| Owner rejects all candidates | Organiser logs all as rejected; deliverable brief unchanged; workflow terminates normally |
| Deliverable brief file missing | Researcher creates `Documents/KnowledgeBase/deliverable_brief.md` with standard header |
## 5. Termination Conditions
Workflow is complete when:
- `deliverable_brief.md` has been updated (or confirmed unchanged if all rejected)
- `rejection_log.md` has been updated
- All temp files are archived to `completed/` or deleted per retention rules
## 6. Cross-References
- `.claude/skills/kb-append/SKILL.md` — for YAML schema conventions
- `AI Team/Workflows/memory-system.md` — for temp file archiving rules
---
*Version: 0.1 | Created: 2026-05-14 | Trigger: New source document provided*
Desk Check (Phase 1): Read aloud. Identified a gap: the Organiser’s “category assignment” criterion is not defined. Added a note that categories are drawn from a controlled vocabulary listed in Documents/KnowledgeBase/category_vocab.txt.
Dry Run (Phase 2): Created a mock temp_candidates.yaml with three entries, two of which had near-identical phrasing (“machine-learning model” vs. “machine learning model”). Confirmed that the Organiser’s deduplication instructions need to specify case-folding and hyphen normalisation. Added that to Step 2.
Component Test (Phase 3): Spawned the Researcher on a real two-page document. Output schema was correct but the page field was omitted on one entry because the fact appeared in a footnote. Added error-handling rule: “If page is unclear, use page: "footnote" and include context.”
Integration Test (Phase 4): Full run on a single source document. Total time: 4 minutes. Handoff from Owner to Researcher worked, but the owner had to manually write YAML, which was error-prone. Fix: changed the owner output to a simple markdown checklist; the Organiser converts it to temp_approved.yaml in a new intermediate step.
Edge Case Test (Phase 5): Removed the source document after Step 1 began. The Researcher correctly returned BLOCKED. Tested all-rejection scenario; workflow terminated gracefully with an updated rejection log. Tested missing deliverable brief file; the Researcher created it correctly.
Iteration (Phase 6): After four integration-test cycles, the workflow stabilised. Changelog appended at the bottom of the file.
The final version incorporates all fixes from testing and is production-ready. It lives at AI Team/Workflows/research-brief-approval.md (hypothetical path for this example).
The following errors appear repeatedly in submitted workflow drafts. Avoid them.
Agent tool (ability to spawn sub-agents) when its job is purely read-only creates unnecessary risk. Conversely, denying Bash or Read to an agent that must scan directories cripples it. Match the tool tier to the role’s actual responsibilities.AI Team/...) with absolute paths (/home/...) in the same workflow confuses both agents and human readers. Choose one convention for prose and reserve absolute paths for executable code blocks only.To make a workflow reusable across different inputs, replace hard-coded filenames and values with bracketed placeholders:
[SOURCE_FILE] — the input document path[TARGET_DIR] — the output directory[START_ID] — the initial identifier for a numbered sequence[ROLE_NAME] — the specific agent role responsible for a stepThe Orchestrator resolves these placeholders at runtime based on the owner’s instruction. Never leave a placeholder unresolved in a live execution.
A workflow becomes a skill when it answers how rather than who/when, and when it is loaded by individual agents rather than followed by the Orchestrator. Promote a workflow to a skill when:
A skill file lives at .claude/skills/[name]/SKILL.md and has a simpler structure than a workflow:
# /skill-name — Brief Description
**Trigger:** [When an agent loads this skill]
**Purpose:** [One sentence]
## Section 1: [Topic]
[Operational instructions]
## Section 2: [Topic]
[Operational instructions]
Skills may include YAML frontmatter if they are machine-parseable, but most canonical skills use the same plain-text header as workflows. The key difference is that skills are loaded by agents via /skill-name, whereas workflows are read by the Orchestrator at trigger moments and injected into briefings.
| Dimension | Workflow | Skill |
|---|---|---|
| Question answered | Who does what, and when? | How do I perform this operation? |
| Consumer | Orchestrator | Individual agent |
| Location | AI Team/Workflows/*.md |
.claude/skills/[name]/SKILL.md |
| Invocation | Read at trigger moment | Loaded with /skill-name |
| Structure | Multi-role, multi-step, handoffs | Single-purpose, operational only |
| Example | mining-orchestration.md |
/kb-append, /mining |
The system does not use a central registry or database for workflow discovery. The Orchestrator finds workflows by filesystem inspection within AI Team/Workflows/. When a trigger condition occurs, the Orchestrator either:
CLAUDE.md or its own memory (e.g., load mining-orchestration.md when the owner says “begin mining”), orThis means workflow filenames must be descriptive and predictable. An owner searching for “how sessions are logged” should find session-logging.md immediately.
The canonical index is maintained at AI Team/Index_generated.md. It is refreshed by running:
bash "AI Team/generate-index.sh"
After creating a new workflow, run this script to update the index. The index is a machine-readable catalogue of all workflows and skills, but it is not the primary discovery mechanism — filenames and the Orchestrator’s memory are.
When briefing an agent, the Orchestrator includes the workflow filename explicitly: “Load AI Team/Workflows/mining-orchestration.md and follow the Batch Mining (Papers) section.” Agents should read the specified file as part of their task briefing.
Agents load skills with the slash syntax: /skill-name. This resolves to .claude/skills/[name]/SKILL.md. The Orchestrator does not need to specify the full path; the slash shorthand is sufficient. Example briefing instruction: “Before touching the knowledge base, load /kb-append and follow its backup protocol.”
Version: 1.0 | Created: 2026-05-14 | Trigger: workflow construction and testing
ClassroomAI is a ready-to-use AI team that lives on your own computer. It is built around Claude Code and Ollama cloud models, pre-configured so you can start working immediately — no programming knowledge required. You get three specialised agents (STEVE the coordinator, ZACK the researcher, and NOLAN the team builder) who work together to help you research, analyse, and write.
This tool is designed for students and researchers who want hands-on experience with AI agentic orchestration. Use it for any personal or academic project where a structured research workflow helps.
INSTALL.bat, Mac: INSTALL.command, Chromebook: INSTALL.desktop).This installer downloads and installs free, open-source, and/or freely available software. All components are fetched from their official sources only.
| Component | Description | License | Source |
| Git | Distributed version control system | GPL-2.0+ | git-scm.com |
| Python 3.12 | Programming language and runtime | PSF License | python.org |
| Node.js LTS | JavaScript runtime environment | MIT | nodejs.org |
| Ollama | Local AI model server with cloud model support | MIT | ollama.com |
| Claude Code | AI coding assistant by Anthropic | Anthropic Terms of Service | anthropic.com/claude-code |
Once installed, open your shortcut and type: “Hello! Who are you?” Your team will introduce themselves and you can start working.
The agents can remember what they learn and improve over time.* During installation, you will be asked if you want to include a pre-built basic memory configuration. If you choose yes, the agents will retain notes and preferences across sessions, provided you remember to tell the orchestrator to start and close session. If you choose no, you start with a blank slate and can set up memory manually later.
Persistent memory in multi-agent AI systems involves significant technical challenges. For a full discussion of the memory problem, how it affects agent behaviour, and how this system addresses it, see:
Memory in a Multi-Agent AI System: Problems and Solutions
*Memory persistence requires choosing the pre-built configuration during installation. Full technical details available in the linked document above.
A practical methodology for constructing a lightweight, agent-assisted Translation Management System using SQLite, Python, and structured workflows. Covers database design, quality assurance with MQM, file-system architecture, and a phased implementation roadmap for students and freelance translators.