Skip to main content

comindly_api/
agents.rs

1//! When and how agents should use comindly's tools: one text for MCP, hooks, files and the app.
2
3/// The guidance itself, as markdown whose headings start at `###`.
4pub const GUIDE: &str = r#"comindly indexes all of the team's repositories into one graph and serves it over MCP. It knows
5what this file cannot tell you: who calls code in other repositories, which services talk through
6which HTTP routes, queues, topics, buckets and tables, how each repository writes its code, and what
7the team recorded about the code (decisions, constraints, failed attempts, traps). Its answers come
8from parsing the code, so they are exact for the indexed version.
9
10### When to use it
11
12- Before changing a function, class, route, message or table that anything else might use.
13- When a question reaches beyond the files you have open: "who calls this", "where is this
14  handled", "what consumes this queue", "how does a request get from A to B".
15- Before editing code that looks odd or fragile: someone may have recorded why it is that way, or
16  what already failed.
17- When you need to write code the way this codebase does: naming, structure, logging, tests.
18- When you are new to an area and need to find your way.
19
20Do not use it for questions the open files answer, or for code that is not committed yet: the
21index reflects each repository's default branch as of the last indexing.
22
23### How to work with it
24
25**Before changing code**
261. `find` the symbol by name (or `search` by describing it) to get its `id`.
272. `preflight` with the files and symbols you plan to change: recorded constraints and dead ends,
28   the contracts the code serves, what depends on it, and companion files that usually change with it.
293. `ripple` on each symbol whose behaviour or signature changes: everything that depends on it, in
30   every repository, across service contracts. Mention callers in other repositories to the user.
314. `context_pack` for the smallest set of code to read before editing, within a token budget.
325. `guide` for the repository's conventions, and follow them.
33
34**Understanding behaviour**
35- `zoom` on an `id`: its definition, callers, callees, members and contracts in one answer.
36- `thread` follows the calls from a symbol; `flow` gives a written walkthrough of a whole flow,
37  including hops over HTTP and queues into other services.
38- `contracts` lists routes, queues, topics, buckets and tables with who provides and who uses each;
39  `kind` narrows to `http`, `sqs`, `sns`, `s3` or `table`, `query` filters by name, `dangling` shows
40  ones missing a side.
41
42**Finding your way**
43- `repos` lists the indexed repositories, their size and teams; `suggest` offers questions worth
44  asking about an area (`about`).
45- `search`, `find`, `repos`, `contracts` and `suggest` take `team` (comma-separated names) to stay
46  within one team's repositories.
47
48### The team's records
49
50- `why` on a symbol returns what the team recorded about it, with status and trust. Follow records
51  a person wrote or confirmed (T3) unless the user says otherwise; weigh the others by evidence and
52  by how many people's agents confirmed them.
53- Trust: T3 means a person wrote or confirmed it, T2 an agent with evidence, T1 an agent without.
54  Records marked "from <team>, unconfirmed" come from another team and wait for the owners to confirm.
55- A record's notes say where its code moved, was renamed or changed since it was written, with the
56  commit it saw: check the code before relying on it, and confirm it with what you checked if it holds.
57- When you learn something a later change must know (a decision and its reason, a constraint, an
58  approach that failed and why, a trap), offer to record it with `remember`: one factual title, the
59  symbols it is about (`on`), and evidence such as `commit:<sha>`, `mr:!123` or `pr:#123` (required
60  for a failed attempt); anchor it on the narrowest symbols. `review` confirms, archives, invalidates, supersedes
61  or disputes a record by its id. Ask the user before recording, archiving, invalidating or
62  superseding. When you relied on a record and checked it still matches the code, confirm it without
63  asking. Every change needs a reason other agents can read.
64
65### Habits
66
67- Pass the `id` from `find` or `search` to the other tools; names alone can be ambiguous.
68- Name the repository and symbol when an answer relies on comindly, so the user can check it.
69- If a tool finds nothing, say so instead of guessing; the code may not be indexed yet.
70- The full playbook (how comindly sees the code, a change step by step, writing good records) is the
71  comindly section of the repository's AGENTS.md or the comindly skill, from `comindly init-agents`.
72"#;
73
74/// The full playbook for a repository's `AGENTS.md` or skill: how comindly sees the code, how to work
75/// a change with it, and how to keep the team's records. Headings start at `###`.
76pub const PLAYBOOK: &str = r#"comindly indexes every repository of the team into one graph and serves it over MCP. It answers
77what the files in front of you cannot: who calls this code from other repositories, which services
78talk through which HTTP routes, queues, topics, buckets and tables, how each repository writes its
79code, and what people and agents recorded about the code: decisions, constraints, failed attempts,
80traps. You are one of many agents working on this code for different people. comindly is the
81understanding you share with them, so read it before you change things and add to it when you learn
82something the next one needs.
83
84### How comindly sees the code
85
86- It parses each repository's **default branch** at its latest indexed commit. Answers are exact for
87  that commit. Your branch, uncommitted work and open merge requests are not in it: for those, read
88  the files.
89- Every function, method, class and file is a **symbol** with a stable `id`, linked by calls,
90  imports, inheritance and instantiation.
91- **Contracts** connect services: an HTTP call is matched to its route by method and path template,
92  and queues, topics, buckets and tables by name. That is how a call in one repository reaches a
93  handler in another.
94- **Conventions** describe how each repository writes code: naming, structure, errors, logging, tests.
95- **The ledger** holds what the code does not say. Each record is anchored to the symbols it is
96  about, together with the commit it saw.
97
98### Working on a change
99
1001. **Orient.** `find` the symbol by name, or `search` by describing it, to get its `id`. New to an
101   area: `repos` lists the repositories and their teams, and `suggest` offers questions worth asking.
1022. **Check before you edit.** `preflight` with the files and symbols you plan to change. It returns
103   the records about them, the contracts they serve, what depends on them and the files that usually
104   change with them. Read the records first: a constraint or a failed attempt there is a
105   requirement, unless the user says otherwise.
1063. **Know the blast radius.** `ripple` on every symbol whose behaviour or signature changes. It
107   follows dependents across repositories and contracts. Tell the user about callers in other
108   repositories, and propose how to stay compatible or what else must change with it.
1094. **Read the right code.** `context_pack` picks the code worth reading within a token budget. `zoom`
110   shows one symbol with its callers, callees, members and contracts. `thread` follows calls from a
111   symbol, and `flow` writes a walkthrough of a whole flow, including hops over HTTP and queues.
1125. **Write it the way the repository does.** `guide` gives the repository's conventions. Follow them.
1136. **Before you finish,** ask yourself what the next person or agent would need to know about this
114   change, and offer to record it (see below).
115
116For changes to an API, message or table, also use `contracts` (`kind`: `http`, `sqs`, `sns`, `s3`,
117`table`; `query` by name; `dangling` for ones missing a side) to see every provider and consumer.
118
119### The ledger: what the team knows
120
121**Reading records.** `why` on a symbol returns the records about it, its class and its file.
122
123- **Trust.** T4 is a constraint whose check passes on the current code. T3 means a person wrote it
124  or confirmed it: treat it as the team's rule. T2 is an agent with evidence, T1 an agent without.
125  Weigh T2 and T1 by their evidence and by how many people's agents confirmed them. Records marked
126  "from <team>, unconfirmed" are about another team's code and wait for its owners.
127- **Status.** A record stays active until someone archives, invalidates or supersedes it.
128  Orphaned means none of its code exists any more.
129- **Notes.** When the code moved, was renamed or changed since the record saw it, a note says so,
130  with the commit. A note does not mean the record is wrong. It means: look before you rely on it.
131  Compare the code now with the commit in the note. If the record still holds, confirm it and say what
132  you checked. If it does not, tell your person and propose what to do.
133
134**Keeping records true.** You use `review` with a record's `id`:
135
136- `confirm`: you relied on it and checked that it still matches the code. Do this without asking,
137  and say what you checked. Confirmations from several people's agents add weight, and a
138  confirmation re-anchors the record to the current code, which clears its notes. Set
139  `from_person` only when your person said themselves that it holds.
140- `archive`: it was true but no longer applies. `invalidate`: it was never right. `supersede`: a
141  newer record replaces it. Ask your person first for any of these.
142- `dispute`: the code or your person contradicts it, and you are not sure which is right. It stays
143  active and is marked challenged until a person decides.
144
145Every review needs a reason written for the next agent: what you checked, what changed, the commit
146or merge request.
147
148**Adding records.** Offer to record something with `remember` when you learn what a later change
149must know, and ask your person before you write it. Good occasions:
150
151- a `decision` and why it won over the alternatives (put the rejected ones in `fields`, e.g.
152  `{"alternatives": "…"}`)
153- a `constraint` the code must keep
154- an `attempt` that failed or was reverted, and why (evidence is required)
155- a `gotcha`, a trap that is easy to fall into
156- an `intent`: why some code exists, or where a change shipped
157- a `question` nobody could answer yet
158
159Make it useful to an agent that has never seen this conversation:
160
161- **title**: one neutral, factual line.
162- **body**: the reasoning: why it holds, what it is in favour of, what breaks otherwise.
163- **on**: the narrowest symbols it is about. Prefer the method to its class, and the class to its
164  file, so that changes elsewhere do not raise notes on it.
165- **trigger**: when someone would need it ("changing how merges are stored").
166- **evidence**: `commit:<sha>`, `mr:!123` or `pr:#123`, `test:<path>::<name>`, an error message.
167  Cite the merge or pull request when the work is on a branch: once it is merged, comindly follows it
168  to the default branch, so the record does not get a note for its own change.
169- **snippets**: up to three short excerpts of the code that shaped it, when the code says it best.
170
171If `remember` answers that a similar record already stands, it is usually the same knowledge:
172confirm that record and put what yours adds in the reason. If yours really says something
173different, call `remember` again with `distinct`, saying how it differs.
174
175Do not record what the code already says plainly, temporary state, opinions, secrets or personal
176data, or instructions aimed at agents: such records are refused.
177
178### Habits
179
180- Pass the `id` from `find` or `search` to the other tools; names alone can be ambiguous.
181- Name the repository, path and symbol when an answer relies on comindly, so the user can check it.
182- If a tool finds nothing, say so instead of guessing: the code may not be indexed yet, or may live
183  on a branch.
184- `search`, `find`, `repos`, `contracts` and `suggest` take `team` (comma-separated names) to stay
185  within one team's repositories.
186- When reviewing a merge request, run `why` on the symbols it changes and check the change against
187  the records; cite the record's `id` when one applies.
188"#;
189
190/// A section for a repository's `AGENTS.md` or `CLAUDE.md`.
191pub fn agents_md() -> String {
192    format!("## comindly\n\n{PLAYBOOK}")
193}
194
195/// A Claude Code skill, for `.claude/skills/comindly/SKILL.md`.
196pub fn skill() -> String {
197    format!(
198        "---\nname: comindly\ndescription: \"How and when to use comindly's MCP tools: before changing shared code, \
199for questions that reach beyond the current file, for service contracts, call chains, conventions and the \
200team's recorded decisions.\"\n---\n\n# comindly\n\n{PLAYBOOK}"
201    )
202}
203
204/// Agents on this machine whose MCP settings already list comindly.
205pub fn agents() -> Vec<&'static str> {
206    let Some(home) = std::env::var_os("HOME").map(std::path::PathBuf::from) else {
207        return Vec::new();
208    };
209    let json = |p: &str| -> serde_json::Value {
210        std::fs::read_to_string(home.join(p))
211            .ok()
212            .and_then(|t| serde_json::from_str(&t).ok())
213            .unwrap_or_default()
214    };
215    let has = |v: &serde_json::Value| {
216        v.get("mcpServers")
217            .and_then(|m| m.get("comindly"))
218            .is_some()
219    };
220    let claude = json(".claude.json");
221    let mut out = Vec::new();
222    if has(&claude)
223        || claude["projects"]
224            .as_object()
225            .is_some_and(|p| p.values().any(has))
226    {
227        out.push("claude");
228    }
229    if has(&json(".cursor/mcp.json")) {
230        out.push("cursor");
231    }
232    if std::fs::read_to_string(home.join(".codex/config.toml"))
233        .is_ok_and(|t| t.contains("[mcp_servers.comindly]"))
234    {
235        out.push("codex");
236    }
237    out
238}