maf 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +411 -0
- data/assets/agents-contract.md +80 -0
- data/assets/analyst +240 -0
- data/assets/coord +2936 -0
- data/assets/dashboard +553 -0
- data/assets/dashboard.html +341 -0
- data/assets/dispatcher +1687 -0
- data/assets/doc-graph-refresh +286 -0
- data/assets/env.sh +6 -0
- data/assets/git-hooks/post-commit +7 -0
- data/assets/git-hooks/post-merge +7 -0
- data/assets/git-hooks/pre-commit +32 -0
- data/assets/harness-hooks/board-watch-opencode.js +87 -0
- data/assets/harness-hooks/board-watch.rb +286 -0
- data/assets/harness-hooks/context-watch.rb +268 -0
- data/assets/harness-hooks/next-task-hermes.sh +48 -0
- data/assets/harness-hooks/next-task.rb +97 -0
- data/assets/harness-hooks/session-guard.rb +128 -0
- data/assets/taskrc.append +11 -0
- data/assets/vault +224 -0
- data/assets/worktree-env.example.rb +26 -0
- data/exe/maf +14 -0
- data/install.md +326 -0
- data/lib/maf/bootstrap/claude_settings.rb +55 -0
- data/lib/maf/bootstrap/dependencies.rb +37 -0
- data/lib/maf/bootstrap/git_hook_planner.rb +68 -0
- data/lib/maf/bootstrap/global_taskrc_warning.rb +33 -0
- data/lib/maf/bootstrap/graph_home.rb +62 -0
- data/lib/maf/bootstrap/hook_merger.rb +53 -0
- data/lib/maf/bootstrap/installer.rb +66 -0
- data/lib/maf/bootstrap/layout_planner.rb +18 -0
- data/lib/maf/bootstrap/marked_block.rb +44 -0
- data/lib/maf/bootstrap/memory_branch.rb +77 -0
- data/lib/maf/bootstrap/options.rb +34 -0
- data/lib/maf/bootstrap/project.rb +77 -0
- data/lib/maf/bootstrap/script_planner.rb +81 -0
- data/lib/maf/bootstrap/text_planner.rb +42 -0
- data/lib/maf/bootstrap/vault_starter.rb +41 -0
- data/lib/maf/bootstrap/writer.rb +69 -0
- data/lib/maf/bootstrap.rb +162 -0
- data/lib/maf/budget.rb +59 -0
- data/lib/maf/cli.rb +135 -0
- data/lib/maf/env_exclude.rb +23 -0
- data/lib/maf/flow/agent_links.rb +79 -0
- data/lib/maf/flow/bootstrapper.rb +36 -0
- data/lib/maf/flow/codex_hooks.rb +50 -0
- data/lib/maf/flow/generator.rb +63 -0
- data/lib/maf/flow/harness_linker.rb +37 -0
- data/lib/maf/flow/hermes_hook.rb +48 -0
- data/lib/maf/flow/hermes_hook_setup.rb +69 -0
- data/lib/maf/flow/hook_files.rb +16 -0
- data/lib/maf/flow/hook_installer.rb +33 -0
- data/lib/maf/flow/legacy_codex_hook.rb +71 -0
- data/lib/maf/flow/manifest.rb +51 -0
- data/lib/maf/flow/mcp_config.rb +72 -0
- data/lib/maf/flow/mcp_installer.rb +45 -0
- data/lib/maf/flow/models.rb +61 -0
- data/lib/maf/flow/options.rb +65 -0
- data/lib/maf/flow/prompt_builder.rb +85 -0
- data/lib/maf/flow/prompt_text.rb +263 -0
- data/lib/maf/flow/report.rb +89 -0
- data/lib/maf/flow/role_catalog.rb +40 -0
- data/lib/maf/flow/role_files.rb +72 -0
- data/lib/maf/flow/role_stub.rb +38 -0
- data/lib/maf/flow/roster.rb +28 -0
- data/lib/maf/flow/validator.rb +38 -0
- data/lib/maf/flow/workflow.rb +28 -0
- data/lib/maf/flow.rb +84 -0
- data/lib/maf/local_exclude.rb +53 -0
- data/lib/maf/menu.rb +101 -0
- data/lib/maf/migrate/moves.rb +44 -0
- data/lib/maf/migrate/rewrites.rb +53 -0
- data/lib/maf/migrate/role_files.rb +35 -0
- data/lib/maf/migrate/runner.rb +66 -0
- data/lib/maf/migrate/worktrees.rb +65 -0
- data/lib/maf/migrate.rb +62 -0
- data/lib/maf/prompt.rb +40 -0
- data/lib/maf/retire.rb +116 -0
- data/lib/maf/role_limits.rb +49 -0
- data/lib/maf/setup_agent/args.rb +57 -0
- data/lib/maf/setup_agent/dispatch.rb +44 -0
- data/lib/maf/setup_agent/hermes_launcher.rb +34 -0
- data/lib/maf/setup_agent/hermes_skill.rb +26 -0
- data/lib/maf/setup_agent/launcher.rb +85 -0
- data/lib/maf/setup_agent/manifest.rb +35 -0
- data/lib/maf/setup_agent/project.rb +9 -0
- data/lib/maf/setup_agent/role_file.rb +30 -0
- data/lib/maf/setup_agent/runtime_hooks.rb +37 -0
- data/lib/maf/setup_agent/worktree.rb +50 -0
- data/lib/maf/setup_agent.rb +111 -0
- data/lib/maf/shared/git_exclude.rb +33 -0
- data/lib/maf/shared/git_identity.rb +41 -0
- data/lib/maf/shared/peak_rate.rb +20 -0
- data/lib/maf/shared/processes.rb +31 -0
- data/lib/maf/shared/project.rb +34 -0
- data/lib/maf/shared/roles.rb +19 -0
- data/lib/maf/team.rb +114 -0
- data/lib/maf/team_command.rb +73 -0
- data/lib/maf/uninstall/claude_settings.rb +40 -0
- data/lib/maf/uninstall/codex_hooks.rb +18 -0
- data/lib/maf/uninstall/commit_guard.rb +16 -0
- data/lib/maf/uninstall/coordination.rb +15 -0
- data/lib/maf/uninstall/doc_graph_hooks.rb +38 -0
- data/lib/maf/uninstall/git.rb +13 -0
- data/lib/maf/uninstall/local_files.rb +33 -0
- data/lib/maf/uninstall/manifest.rb +29 -0
- data/lib/maf/uninstall/marked_files.rb +37 -0
- data/lib/maf/uninstall/mcp_entries.rb +43 -0
- data/lib/maf/uninstall/notes.rb +31 -0
- data/lib/maf/uninstall/owned.rb +12 -0
- data/lib/maf/uninstall/role_files.rb +51 -0
- data/lib/maf/uninstall/runner.rb +67 -0
- data/lib/maf/uninstall/scripts.rb +35 -0
- data/lib/maf/uninstall/vault_watcher.rb +21 -0
- data/lib/maf/uninstall/worktrees.rb +30 -0
- data/lib/maf/uninstall.rb +59 -0
- data/lib/maf/untrack.rb +90 -0
- data/lib/maf/version.rb +5 -0
- data/lib/maf/worker_archive.rb +63 -0
- data/lib/maf/worker_control.rb +137 -0
- data/lib/maf/workers.rb +37 -0
- data/lib/maf.rb +5 -0
- data/templates/claude.md.erb +16 -0
- data/templates/codex.md.erb +7 -0
- data/templates/hermes.md.erb +12 -0
- data/templates/opencode.md.erb +24 -0
- data/templates/role-stub.yml.erb +15 -0
- data/templates/roles.yml +289 -0
- data/templates/workflows/panel.md +20 -0
- data/templates/workflows/plan-review.md +9 -0
- data/templates/workflows/simple.md +4 -0
- data/templates/workflows/tdd.md +8 -0
- metadata +193 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 4cdbedeaf3c68e4b2aa40939c8f006f846d0d044531f2c6d53e01cddf4d9e45d
|
|
4
|
+
data.tar.gz: e90a24b66c78fd7cc493e493f722b25a5803430967b2cae0de46202befaf12b2
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ee79aa5c928c7be62ed39cdcf2904f7905b6e33189c31f19b7badd522cd0600431d6b39faebf72c7f60caf951ddbb577efc6d2a1fc167145f4f2503665ffe256
|
|
7
|
+
data.tar.gz: 0aa9875967605035e251dab51a6ad097dc80c428cda40a8db8abfad99d0cb5381d92da1c5b7e9dc5b4daa5d7263e670655150100a40f70fb0ec9369b35f868fe
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-10-08
|
|
6
|
+
|
|
7
|
+
- First release as a gem: `gem install maf`.
|
|
8
|
+
- All code is in the `Maf` module.
|
|
9
|
+
- The command moved from `bin/maf` to `exe/maf`. `bin/maf` stays for the links
|
|
10
|
+
that point to it. A later version removes it.
|
|
11
|
+
- New commands: `maf version` and `maf guide` (prints the agent setup guide).
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dominik Alberski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# multi_agent_flow
|
|
2
|
+
|
|
3
|
+
Coordination layer for running several AI coding agents (opencode, Claude Code,
|
|
4
|
+
Hermes, Codex) in parallel on one repository, each in its own terminal.
|
|
5
|
+
|
|
6
|
+
Three pillars:
|
|
7
|
+
|
|
8
|
+
| Pillar | Implementation |
|
|
9
|
+
|---|---|
|
|
10
|
+
| Communication | Taskwarrior task board + `.maf/coordination/` inbox, via the `coord` CLI |
|
|
11
|
+
| Resource control | `mkdir`-based locks — no `flock`, works on macOS and Linux |
|
|
12
|
+
| Shared memory | graphify knowledge graph + Obsidian vault, served over MCP |
|
|
13
|
+
|
|
14
|
+
The whole layer is **CLI + files**: every harness uses it identically; no GUI or
|
|
15
|
+
vendor dependency.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
The `maf` gem holds the flow. Install these tools yourself:
|
|
22
|
+
|
|
23
|
+
| Tool | Why | Install |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| Ruby 3.0+ | runs `maf`, `coord`, and the other scripts | macOS: `brew install mise && mise install ruby`. Linux: your package manager or [mise](https://mise.jdx.dev) |
|
|
26
|
+
| git | worktrees, hooks, the local exclude file | macOS: `xcode-select --install` or `brew install git`. Linux: `apt install git` |
|
|
27
|
+
| Taskwarrior | the task board | macOS: `brew install task`. Linux: `apt install taskwarrior` |
|
|
28
|
+
| One or more harnesses | the agents | [Claude Code](https://docs.claude.com/en/docs/claude-code), [Codex](https://github.com/openai/codex), [opencode](https://opencode.ai), [Hermes](https://github.com/NousResearch/hermes-agent) |
|
|
29
|
+
| graphify (optional) | the shared knowledge graph | `uv tool install graphifyy` |
|
|
30
|
+
|
|
31
|
+
Install the gem:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
gem install maf
|
|
35
|
+
maf version
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Upgrade the gem. Then run `maf update` in each project: it replaces the flow files with the new versions.
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
gem update maf
|
|
42
|
+
cd ~/Projects/my-app && maf update
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Fast path — agent-driven
|
|
46
|
+
|
|
47
|
+
1. Install the gem: `gem install maf`.
|
|
48
|
+
2. Open any AI coding agent in your project folder and say:
|
|
49
|
+
|
|
50
|
+
> Run `maf guide`. Read the output and implement it.
|
|
51
|
+
|
|
52
|
+
The agent asks which harnesses and roles to use, runs `maf add`, and prints
|
|
53
|
+
the `maf start` commands to start each session.
|
|
54
|
+
|
|
55
|
+
`maf guide` prints **[install.md](install.md)**: the exact instructions that the agent follows.
|
|
56
|
+
|
|
57
|
+
## Manual path - the maf command
|
|
58
|
+
|
|
59
|
+
Run `maf` in the project root.
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
cd ~/Projects/my-app
|
|
63
|
+
maf roles # list the roles
|
|
64
|
+
maf add claude:architect opencode:backend-developer # install the flow and add agents
|
|
65
|
+
maf start claude architect # start one agent in its worktree
|
|
66
|
+
maf help # all commands
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Run `maf` without a command to use the interactive menu. The menu asks for
|
|
70
|
+
each value: harness, roles, models, and the agent to start.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Project layout
|
|
75
|
+
|
|
76
|
+
The flow keeps every file that it owns in one folder, `.maf/`, in the project.
|
|
77
|
+
The knowledge graph is the exception: it is project knowledge, not tooling, so it
|
|
78
|
+
lives in `graphify-out/` at the project root, where graphify looks by default.
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
.maf/
|
|
82
|
+
bin/ coord, dispatcher, vault, dashboard, analyst, doc-graph-refresh
|
|
83
|
+
lib/maf/shared/ code that the scripts in bin/ load (maf update replaces it)
|
|
84
|
+
coordination/ task board, inbox, locks, presence, sessions, hooks, logs
|
|
85
|
+
worktrees/ one git worktree per worker
|
|
86
|
+
agents/ role files: claude/, opencode/, codex/
|
|
87
|
+
claude/ settings.json: the Claude Code hooks (maf start passes --settings)
|
|
88
|
+
mcp/ the graphify MCP server for Claude Code and opencode
|
|
89
|
+
config.json the agents and settings of the project
|
|
90
|
+
roles.yml project roles (you write it; maf role add NAME)
|
|
91
|
+
workflow.md stage instructions for the architect (you write it)
|
|
92
|
+
env.sh source it: puts .maf/bin on PATH
|
|
93
|
+
graphify-out/ knowledge graph (excluded from git; each worktree has a symlink to it)
|
|
94
|
+
memory/ work memory notes: a worktree of the orphan branch maf/memory (ADR 0006)
|
|
95
|
+
obsidian/ generated Obsidian vault
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
maf is a tool, not a part of the project. Nothing that runs maf goes into git:
|
|
99
|
+
`.maf/` and each link and plugin that maf creates are listed in `.git/info/exclude`,
|
|
100
|
+
which is local to the clone. maf never edits a file that the project tracks.
|
|
101
|
+
|
|
102
|
+
The project keeps what the agents make, also after `maf uninstall`:
|
|
103
|
+
|
|
104
|
+
| Path | What it is |
|
|
105
|
+
|---|---|
|
|
106
|
+
| the code | The work of the agents, landed on the goal branches. |
|
|
107
|
+
| `GLOSSARY.md` | The domain glossary. The project manager drafts it. A worker commits it on the architect's task. |
|
|
108
|
+
| `docs/decisions/` | ADRs. The architect decides them. A worker commits them. |
|
|
109
|
+
|
|
110
|
+
Local files that a harness or git reads outside `.maf/`:
|
|
111
|
+
|
|
112
|
+
| Path | Reason |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `.git/hooks/*` | Git reads them there. |
|
|
115
|
+
| `.git/info/exclude` | Keeps the flow out of git in this clone. |
|
|
116
|
+
| `.claude/agents/`, `.opencode/agents/`, `.codex/prompts/` | Symlinks into `.maf/agents/<harness>/`. |
|
|
117
|
+
| `.opencode/plugins/board-watch.js` | opencode reads it there. |
|
|
118
|
+
| `.codex/hooks.json` | Codex reads it there. Excluded when the project does not track it. |
|
|
119
|
+
| `~/.hermes/skills/<project>-<role>/SKILL.md` | Hermes reads it there. |
|
|
120
|
+
|
|
121
|
+
Claude Code gets the hooks from `.maf/claude/settings.json` (`--settings`) and the
|
|
122
|
+
graphify MCP server from `.maf/mcp/claude.json` (`--mcp-config`). opencode gets the
|
|
123
|
+
server from `.maf/mcp/opencode.json` (`OPENCODE_CONFIG`). `maf start` and the
|
|
124
|
+
dispatcher pass these files. The project's `.claude/settings.json`, `.mcp.json`,
|
|
125
|
+
`opencode.json`, `AGENTS.md`, and `CLAUDE.md` stay as they are.
|
|
126
|
+
|
|
127
|
+
MAF installs Codex hooks in the project `.codex/hooks.json` file.
|
|
128
|
+
Hooks act only on sessions that `maf start` registers.
|
|
129
|
+
Each hook checks the launch token, process, worktree, role, worker, board, and harness session ID.
|
|
130
|
+
An independent session does not activate hooks, even with inherited coordination variables.
|
|
131
|
+
`maf update` disables the legacy global Codex hook and removes only its registration.
|
|
132
|
+
Other global hooks stay.
|
|
133
|
+
Restart workers with `maf start` after the update.
|
|
134
|
+
|
|
135
|
+
A project with the old layout runs `maf migrate` once. See the migration
|
|
136
|
+
section of [USER_MANUAL.md](USER_MANUAL.md).
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Documentation
|
|
141
|
+
|
|
142
|
+
| File | Audience | What it covers |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| **[docs/flow-glossary.md](docs/flow-glossary.md)** | Everyone | Flow terms: harness, role, worker, agent, task, message, claim, lock, hooks. [docs/flow-cli-names.md](docs/flow-cli-names.md) lists their names in code and CLI |
|
|
145
|
+
| **[GETTING_STARTED.md](GETTING_STARTED.md)** | First-time user | Concepts, prerequisites, manual install, basic workflow |
|
|
146
|
+
| **[USER_MANUAL.md](USER_MANUAL.md)** | Setting up a real team | Full install (maf), all harnesses, dispatcher, monitoring |
|
|
147
|
+
| **[install.md](install.md)** | An AI coding agent | Interactive wizard: asks the user for harnesses/roles, runs `maf add` |
|
|
148
|
+
| **[docs/out-of-scope.md](docs/out-of-scope.md)** | Contributor | Requests that the project rejects on purpose, with the reason |
|
|
149
|
+
| **[SKILL.md](SKILL.md)** | Agent skill loader | Self-contained portable skill (frontmatter + full API reference) |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Contents
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
multi_agent_flow/
|
|
157
|
+
install.md # agent instruction: interactive setup wizard
|
|
158
|
+
SKILL.md # portable skill for agent skill loaders
|
|
159
|
+
README.md # this file
|
|
160
|
+
docs/flow-glossary.md # flow terms
|
|
161
|
+
docs/flow-cli-names.md # code and CLI name of each flow term
|
|
162
|
+
GETTING_STARTED.md # first-time walkthrough (concepts + manual setup)
|
|
163
|
+
USER_MANUAL.md # full team setup reference
|
|
164
|
+
maf.gemspec # the gem: files, version, the webrick dependency
|
|
165
|
+
Gemfile # development gems: rake, minitest, rubocop
|
|
166
|
+
CHANGELOG.md # changes per version
|
|
167
|
+
exe/
|
|
168
|
+
maf # the maf command line tool (gem install maf puts it on PATH)
|
|
169
|
+
bin/
|
|
170
|
+
maf # old path of the command; loads exe/maf
|
|
171
|
+
setup # bundle install
|
|
172
|
+
console # irb with maf loaded
|
|
173
|
+
lib/maf.rb # require "maf" loads the command line tool
|
|
174
|
+
lib/maf/
|
|
175
|
+
version.rb # Maf::VERSION
|
|
176
|
+
cli.rb # maf subcommands
|
|
177
|
+
menu.rb # interactive menu (maf without a command)
|
|
178
|
+
prompt.rb # numbered terminal questions for the menu
|
|
179
|
+
flow.rb # generates harness-specific role files + installs coordination layer
|
|
180
|
+
bootstrap.rb # idempotent coordination layer installer
|
|
181
|
+
setup_agent.rb # maf start: worktree + harness launch
|
|
182
|
+
uninstall.rb # removes the flow from a project; keeps graphify-out/
|
|
183
|
+
migrate.rb # maf migrate: moves an old-layout install into .maf/
|
|
184
|
+
team.rb # maf prepare: adds or replaces one worker
|
|
185
|
+
team_command.rb # maf team: shows the team, or sets its budget
|
|
186
|
+
retire.rb # maf retire: removes one worker and archives its state
|
|
187
|
+
worker_control.rb # maf worker: stops, starts, or restarts one worker
|
|
188
|
+
flow/role_catalog.rb # merges .maf/roles.yml over the built-in roles
|
|
189
|
+
flow/workflow.rb # reads .maf/workflow.md for the architect prompt
|
|
190
|
+
flow/mcp_config.rb # writes the graphify MCP server into .maf/mcp/
|
|
191
|
+
untrack.rb # maf untrack: removes an older install from git
|
|
192
|
+
local_exclude.rb # the flow block in .git/info/exclude
|
|
193
|
+
shared/ # stdlib-only code that the maf CLI and the scripts share (installed as .maf/lib/maf/shared/)
|
|
194
|
+
scripts/
|
|
195
|
+
check.rb # repo consistency check (UDA sync, markers, script signatures)
|
|
196
|
+
templates/
|
|
197
|
+
roles.yml # role definitions + model hints
|
|
198
|
+
role-stub.yml.erb # stub that maf role add writes
|
|
199
|
+
workflows/ # default workflows: simple, plan-review, tdd, panel
|
|
200
|
+
opencode.md.erb # role file templates per harness
|
|
201
|
+
claude.md.erb
|
|
202
|
+
codex.md.erb
|
|
203
|
+
hermes.md.erb
|
|
204
|
+
assets/
|
|
205
|
+
coord # coordination CLI (Ruby)
|
|
206
|
+
dispatcher # polls task board + inbox, starts one-shot agents (Ruby)
|
|
207
|
+
vault # graphify + Obsidian + MCP watcher control, graph age (Ruby)
|
|
208
|
+
dashboard # web dashboard: workers table with actions, alerts, board (Ruby/WEBrick)
|
|
209
|
+
analyst # asks a small model for token hints about one worker (dashboard analyze button)
|
|
210
|
+
doc-graph-refresh # graphify rebuild runner called by the git hooks (Ruby)
|
|
211
|
+
env.sh # shell environment: .maf/bin on PATH (installed as .maf/env.sh)
|
|
212
|
+
git-hooks/ # pre-commit guard, post-commit/post-merge refresh blocks
|
|
213
|
+
taskrc.append # Taskwarrior UDA block
|
|
214
|
+
agents-contract.md # coordination contract at the end of each role prompt
|
|
215
|
+
harness-hooks/ # next-task, board-watch, session-guard, and context-watch scripts, and the opencode plugin
|
|
216
|
+
test/
|
|
217
|
+
coord_test.rb # behavioral tests for the coord CLI
|
|
218
|
+
installer_test.rb # tests for bootstrap.rb, flow.rb, setup_agent.rb
|
|
219
|
+
maf_test.rb # tests for the maf command
|
|
220
|
+
dashboard_test.rb # tests for the dashboard data
|
|
221
|
+
dispatcher_test.rb # tests for the dispatcher
|
|
222
|
+
uninstaller_test.rb # tests for uninstall.rb
|
|
223
|
+
migrate_test.rb # tests for migrate.rb
|
|
224
|
+
roles_workflow_test.rb # tests for project roles and the workflow
|
|
225
|
+
graph_age_test.rb # tests for vault age and the graph prompt rules
|
|
226
|
+
mcp_test.rb # tests for the MCP server wiring
|
|
227
|
+
doc_graph_refresh_test.rb # tests for the doc-graph refresh script
|
|
228
|
+
board_watch_test.rb # tests for the board watcher
|
|
229
|
+
context_watch_test.rb # tests for the context-watch hook
|
|
230
|
+
hook_session_test.rb # tests for session isolation
|
|
231
|
+
hook_config_test.rb # tests for project hooks
|
|
232
|
+
worker_control_test.rb # tests for maf worker
|
|
233
|
+
untrack_test.rb # tests for maf untrack
|
|
234
|
+
analyst_test.rb # tests for the analyst
|
|
235
|
+
shared_test.rb # tests for lib/maf/shared/
|
|
236
|
+
gemspec_test.rb # tests that the gem holds every runtime file
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Use as a skill
|
|
242
|
+
|
|
243
|
+
Copy or symlink this directory into a skills location so agents can discover it.
|
|
244
|
+
The skill loader matches the folder name to `name:` in the frontmatter; the
|
|
245
|
+
installed folder must be `multi-agent-flow` (hyphen, not underscore):
|
|
246
|
+
|
|
247
|
+
```sh
|
|
248
|
+
cp -R "$PWD" ~/.config/opencode/skills/multi-agent-flow
|
|
249
|
+
# or, for Claude Code:
|
|
250
|
+
cp -R "$PWD" ~/.claude/skills/multi-agent-flow
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The skill runs the `maf` command. Install the gem first: `gem install maf`.
|
|
254
|
+
Restart the agent to load the skill. You can also hand `SKILL.md` plus `assets/`
|
|
255
|
+
to any agent as direct context.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Doc-graph refresh
|
|
260
|
+
|
|
261
|
+
A commit or merge that changes a markdown file refreshes the shared knowledge
|
|
262
|
+
graph. `maf add` appends a flow block to the `post-commit` and `post-merge`
|
|
263
|
+
hooks. The block starts `.maf/bin/doc-graph-refresh` detached, so the commit
|
|
264
|
+
returns at once.
|
|
265
|
+
|
|
266
|
+
The refresh runs `graphify extract . --backend gemini` and then
|
|
267
|
+
`graphify export obsidian --dir graphify-out/obsidian`. The graph lives in `graphify-out/`
|
|
268
|
+
at the project root. It builds in a temp dir and swaps the derived files on
|
|
269
|
+
success, so a failed extract keeps the old graph. The swap never replaces
|
|
270
|
+
`graphify-out/memory/` or `graphify-out/obsidian/`. It then runs `graphify reflect` on the
|
|
271
|
+
saved notes. It needs `GEMINI_API_KEY`.
|
|
272
|
+
Without the key it logs a skip in `.maf/coordination/doc-graph.log` and exits. A
|
|
273
|
+
non-markdown commit makes no LLM call. A refresh started in a worktree writes
|
|
274
|
+
the shared graph in the main checkout.
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Contributor reference
|
|
279
|
+
|
|
280
|
+
After editing the UDA block or the worktree-path formula:
|
|
281
|
+
|
|
282
|
+
```sh
|
|
283
|
+
ruby scripts/check.rb
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Verifies: the UDA block in `assets/coord` matches `assets/taskrc.append`; the
|
|
287
|
+
markers are present; the worktree path formula is identical in `assets/coord`
|
|
288
|
+
and `lib/maf/setup_agent/worktree.rb`; each script carries its signature; and the
|
|
289
|
+
literals that the standalone scripts share (lead roles, read-only toolsets,
|
|
290
|
+
the report format, the presence start time) are identical.
|
|
291
|
+
|
|
292
|
+
Install the development gems once:
|
|
293
|
+
|
|
294
|
+
```sh
|
|
295
|
+
bin/setup # bundle install
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Run the checks and all tests:
|
|
299
|
+
|
|
300
|
+
```sh
|
|
301
|
+
bundle exec rake # scripts/check.rb, RuboCop, then all tests
|
|
302
|
+
bundle exec rake lint # RuboCop only
|
|
303
|
+
bundle exec rake test TEST=test/coord_test.rb # one test file
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
To use maf from the clone, link `exe/maf` into a folder on `PATH`:
|
|
307
|
+
|
|
308
|
+
```sh
|
|
309
|
+
ln -sf "$PWD/exe/maf" ~/.local/bin/maf
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Build and install the gem from the clone:
|
|
313
|
+
|
|
314
|
+
```sh
|
|
315
|
+
bundle exec rake build # writes pkg/maf-VERSION.gem
|
|
316
|
+
bundle exec rake install # builds and installs the gem
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
To release, change `Maf::VERSION` in `lib/maf/version.rb` and add a
|
|
320
|
+
`CHANGELOG.md` entry.
|
|
321
|
+
|
|
322
|
+
RuboCop (pinned in the `Gemfile`) uses `.rubocop.yml`. It sets the
|
|
323
|
+
size rules: a class at most 100 lines, a method at most 5 lines and 4
|
|
324
|
+
parameters, a line at most 120 characters. `.rubocop_todo.yml` lists the code
|
|
325
|
+
that broke a rule before the config existed. Fix an entry, then delete it.
|
|
326
|
+
Do not add new entries.
|
|
327
|
+
|
|
328
|
+
`rake test` runs each test file in its own process, in parallel, and prints the
|
|
329
|
+
output of a failed file only. It unsets the variables below for each test.
|
|
330
|
+
|
|
331
|
+
An agent session exports `TASKRC` and `COORD_DIR` for the shared board. Unset
|
|
332
|
+
them when you run a test file directly, so a test never writes to that board:
|
|
333
|
+
|
|
334
|
+
```sh
|
|
335
|
+
env -u TASKRC -u COORD_DIR -u COORD_ROLE -u COORD_WORKER ruby test/coord_test.rb
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
```sh
|
|
339
|
+
ruby test/coord_test.rb # covers the coord CLI
|
|
340
|
+
ruby test/installer_test.rb # covers bootstrap.rb, flow.rb, setup_agent.rb
|
|
341
|
+
ruby test/uninstaller_test.rb # covers uninstall.rb
|
|
342
|
+
ruby test/migrate_test.rb # covers migrate.rb
|
|
343
|
+
ruby test/roles_workflow_test.rb # covers project roles and the workflow
|
|
344
|
+
ruby test/graph_age_test.rb # covers vault age and the graph prompt rules
|
|
345
|
+
ruby test/mcp_test.rb # covers the MCP server wiring
|
|
346
|
+
ruby test/maf_test.rb # covers the maf command
|
|
347
|
+
ruby test/dashboard_test.rb # covers the dashboard data
|
|
348
|
+
ruby test/doc_graph_refresh_test.rb # covers the doc-graph refresh
|
|
349
|
+
ruby test/hook_session_test.rb # covers session isolation
|
|
350
|
+
ruby test/hook_config_test.rb # covers project hooks and legacy hook removal
|
|
351
|
+
ruby test/dispatcher_test.rb # covers the dispatcher
|
|
352
|
+
ruby test/board_watch_test.rb # covers the board watcher
|
|
353
|
+
ruby test/context_watch_test.rb # covers the context-watch hook
|
|
354
|
+
ruby test/worker_control_test.rb # covers maf worker
|
|
355
|
+
ruby test/untrack_test.rb # covers maf untrack
|
|
356
|
+
ruby test/analyst_test.rb # covers the analyst
|
|
357
|
+
ruby test/shared_test.rb # covers lib/maf/shared/
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Minitest, stdlib only. Tests that require `task`, `git`, or `node` skip (exit 0)
|
|
361
|
+
when those tools are absent. The dashboard tests need the `webrick` gem.
|
|
362
|
+
CI (`.github/workflows/test.yml`) installs all of them and runs the checks and
|
|
363
|
+
tests on Linux and macOS, and RuboCop, for each push to `main` and each pull
|
|
364
|
+
request.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Design notes
|
|
369
|
+
|
|
370
|
+
- **Taskwarrior is the single source of truth**, in a project-local database
|
|
371
|
+
(`.maf/coordination/taskdata`, via `.maf/coordination/taskrc`) — never the user's
|
|
372
|
+
global `~/.task`. Two projects on this flow never share one board.
|
|
373
|
+
`coord board`/`export` are read-only projections.
|
|
374
|
+
- **Agents never call `task` directly.** `coord` keeps the protocol stable and
|
|
375
|
+
lets the storage backend change later.
|
|
376
|
+
- **Terminology:** see [docs/flow-glossary.md](docs/flow-glossary.md). One role can run as several
|
|
377
|
+
workers. `claim` is atomic, so two workers cannot take the same task.
|
|
378
|
+
- **A claim is a lease.** Idle past `COORD_LEASE_TTL` seconds (default 4 hours)
|
|
379
|
+
it becomes claimable again without `--force`. `coord unclaim` releases one on
|
|
380
|
+
demand.
|
|
381
|
+
- **Worktrees live inside the project** at `.maf/worktrees/<role>-<worker_id>`.
|
|
382
|
+
`.maf/worktrees/` is excluded from git. In each worktree, run `source .maf/env.sh` so
|
|
383
|
+
`COORD_DIR` and `TASKRC` point at the main project; every worktree shares one
|
|
384
|
+
`.maf/coordination/` dir and one task board.
|
|
385
|
+
- **Scope overlap** is checked on `coord add` (warning) and `coord conflicts`
|
|
386
|
+
(report). It is a path-prefix heuristic, not a full glob matcher. Scope is
|
|
387
|
+
advisory: nothing but agent discipline stops a write outside it, except that
|
|
388
|
+
roles with `can_edit: false` get a restricted tool grant where the harness
|
|
389
|
+
supports one (Claude Code, opencode, Hermes), and the git `pre-commit` guard
|
|
390
|
+
refuses their commits.
|
|
391
|
+
- **The `ollama` lock** is required when one local model host serves several
|
|
392
|
+
agents. Exclusion is TTL-based: coord stores no pid. A lock is reclaimed once its
|
|
393
|
+
TTL elapses (default 3600s), even if the holder is still alive. A killed
|
|
394
|
+
holder keeps the lock until the TTL elapses.
|
|
395
|
+
- **The `project-manager` role** is the user's proxy: the user talks to it, it
|
|
396
|
+
creates goals (`coord goal add`), sends them to the architect, and relays the report back. Without
|
|
397
|
+
`project-manager`, the user talks to the architect directly.
|
|
398
|
+
- **Rejected requests are logged.** When you reject a request on purpose, add
|
|
399
|
+
an entry to [docs/out-of-scope.md](docs/out-of-scope.md): the request, the
|
|
400
|
+
date, the source, and the reason. Read the log before you propose a feature.
|
|
401
|
+
- **UI is deliberately deferred**: Obsidian (Kanban/Dataview) or
|
|
402
|
+
`taskwarrior-tui` can read the same data without any agent changes.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Acknowledgements
|
|
407
|
+
|
|
408
|
+
- The `panel` workflow and the `skeptic` and `auditor` roles come from
|
|
409
|
+
[shipyard](https://github.com/esse/shipyard) by Piotr Szmielew. Shipyard sends
|
|
410
|
+
a plan and a branch to adversarial reviewers from different model families.
|
|
411
|
+
The rules for critical findings and cited lines also come from shipyard.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<!-- >>> multi-agent-flow >>> -->
|
|
2
|
+
## Multi-agent coordination
|
|
3
|
+
|
|
4
|
+
This project uses `coord`, a shared task board for several coding agents.
|
|
5
|
+
Run `source .maf/env.sh` once. It puts `coord` on `PATH` and points `COORD_DIR` at the shared board.
|
|
6
|
+
Use `coord`. Never use raw `task`.
|
|
7
|
+
Your role file holds your work loop. This section holds the terms and rules that all roles share.
|
|
8
|
+
|
|
9
|
+
### Terms
|
|
10
|
+
|
|
11
|
+
- A role is a project function, for example `backend-developer`. A task belongs to a role.
|
|
12
|
+
- A worker is one instance of a role, for example `backend-1`. `COORD_ROLE` and `COORD_WORKER` identify you.
|
|
13
|
+
- A goal is one user-visible outcome. A goal has the branch `goal/<short-id>`.
|
|
14
|
+
- A task is one part of a goal. A worker does the task on the branch `task/<short-id>`.
|
|
15
|
+
- The lead roles are the project manager and the architect. A lead role never claims a task and never commits.
|
|
16
|
+
- Use the terms of the project glossary, `GLOSSARY.md` at the repository root.
|
|
17
|
+
|
|
18
|
+
### Hierarchy
|
|
19
|
+
|
|
20
|
+
If the project has a project manager, the user talks only to the project manager.
|
|
21
|
+
The project manager sends each goal to the architect.
|
|
22
|
+
The architect splits the goal into tasks, lands the done tasks, and reports back.
|
|
23
|
+
Workers never talk to the user. Workers ask the architect with `coord msg`.
|
|
24
|
+
|
|
25
|
+
### Commands
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
coord show ID # one task: its fields and annotations (the task spec)
|
|
29
|
+
coord next [ROLE] [--wait] | --mine # unclaimed tasks, or your claimed tasks
|
|
30
|
+
coord claim ID | start-task ID | done ID # take a task, check out its branch, finish it
|
|
31
|
+
coord annotate ID TEXT # add a note to a task
|
|
32
|
+
coord lesson ID dead_end|corrected TEXT # an approach that failed, or the right way: the graph keeps it
|
|
33
|
+
coord escalate [--task ID] TEXT # a problem you cannot fix: the project manager asks the user
|
|
34
|
+
coord msg --from A [--task ID] [--fyi] TO TEXT # message a role or a worker; --task also notes the task
|
|
35
|
+
# --fyi: no run starts; the next run of TO reads it
|
|
36
|
+
coord broadcast --from A [--to workers|leads|all] TEXT
|
|
37
|
+
coord inbox [ROLE] [--wait] # read your messages
|
|
38
|
+
coord await # interactive Codex: arm the stop hook, then end your turn
|
|
39
|
+
coord goal list | goal show ID # open goals, or one goal and its tasks
|
|
40
|
+
coord who | status | log [N] # live workers, tasks by role, recent events
|
|
41
|
+
coord with-lock NAME -- CMD # run a command under a lock
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If a dispatcher serves your role, the prompt holds your messages. Do not run `coord inbox` then.
|
|
45
|
+
|
|
46
|
+
A worker has no inbox of its own. A message for a worker goes to the inbox of its role.
|
|
47
|
+
Any worker of the role can read it. The `for:` line names the worker.
|
|
48
|
+
If a message is about a task, send it with `--task ID`. The text then also stays as a note on the task.
|
|
49
|
+
If a message names a task that you do not hold, run `coord show ID` before you act.
|
|
50
|
+
|
|
51
|
+
### Rules
|
|
52
|
+
|
|
53
|
+
1. One writer per path. The task scope lists the paths that you own. Never edit outside the scope.
|
|
54
|
+
2. A role with `can_edit: false` cannot commit. The git `pre-commit` hook refuses the commit.
|
|
55
|
+
3. Run each local model generation under the `ollama` lock: `coord with-lock ollama -- <command>`.
|
|
56
|
+
4. Run each command that needs a shared resource (browser, system tests, one fixed port) under one lock:
|
|
57
|
+
`coord with-lock system-test -- <command>`. Do not invent other lock names.
|
|
58
|
+
5. Each worktree has its own test database and server port. Do not share a test database.
|
|
59
|
+
|
|
60
|
+
### Tests
|
|
61
|
+
|
|
62
|
+
- Task tests: the unit tests and the tests for the changed behavior. The worker runs them before the report.
|
|
63
|
+
- Merge suite: the full suite, with system tests. Only the architect runs it, one time per goal.
|
|
64
|
+
- The reviewer does not run tests. The reviewer reads the TESTS line of the report.
|
|
65
|
+
|
|
66
|
+
### Handoff artifacts
|
|
67
|
+
|
|
68
|
+
- A shared working file is an artifact. Write it to `$COORD_DIR/artifacts/<goal>/<name>.md`.
|
|
69
|
+
Run `mkdir -p` for the folder first.
|
|
70
|
+
- Never write an artifact inside a worktree. Worktrees do not share files.
|
|
71
|
+
- A worker commits each durable artifact (an approved spec, an ADR) on the goal branch.
|
|
72
|
+
|
|
73
|
+
### Domain documentation
|
|
74
|
+
|
|
75
|
+
- `GLOSSARY.md` holds domain terms only. The file does not exist until the first term resolves.
|
|
76
|
+
- Each term has a bold name, one or two sentences, and an optional `_Avoid_` line for rejected words.
|
|
77
|
+
- The decisions folder holds the ADRs: `.agent/decisions/` if it exists, else `docs/decisions/`.
|
|
78
|
+
Append. Never rewrite an ADR.
|
|
79
|
+
- `graphify-out/obsidian/` is rebuilt from the code graph. Do not keep permanent notes there.
|
|
80
|
+
<!-- <<< multi-agent-flow <<< -->
|