@vpxa/aikit 0.1.36 → 0.1.38

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vpxa/aikit",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "type": "module",
5
5
  "description": "Local-first AI developer toolkit — knowledge base, code analysis, context management, and developer tools for LLM agents",
6
6
  "license": "MIT",
@@ -1 +1 @@
1
- import{existsSync as e,readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i}from"node:url";import{AIKIT_PATHS as a,createLogger as o,getPartitionDir as s,isUserInstalled as c,registerWorkspace as l,serializeError as u}from"../../core/dist/index.js";const d=n(i(import.meta.url)),f=o(`server`),p=[`auto`,`manual`,`smart`];function m(e){return typeof e==`string`&&p.includes(e)}function h(e,t,n){let i=r(e),a=r(t);if(!i.startsWith(a))throw Error(`Config ${n} path escapes workspace root: ${e} is not under ${t}`);return i}function g(e){let t=process.env.AIKIT_INDEX_MODE;if(m(t))return t;if(e.indexMode)return e.indexMode;let n=process.env.AIKIT_AUTO_INDEX;return n===void 0?e.autoIndex===void 0?`smart`:e.autoIndex?`auto`:`manual`:n===`true`?`auto`:`manual`}function _(){let i=process.env.AIKIT_CONFIG_PATH??(e(r(process.cwd(),`aikit.config.json`))?r(process.cwd(),`aikit.config.json`):r(d,`..`,`..`,`..`,`aikit.config.json`));try{if(!e(i))return f.info(`No config file found, using defaults`,{configPath:i}),v();let o=t(i,`utf-8`),s=JSON.parse(o);if(!s.sources||!Array.isArray(s.sources)||s.sources.length===0)throw Error(`Config must have at least one source`);if(!s.store?.path)throw Error(`Config must specify store.path`);if(s.autoIndex!==void 0&&typeof s.autoIndex!=`boolean`)throw Error(`Config autoIndex must be a boolean`);if(s.indexMode!==void 0&&!m(s.indexMode))throw Error(`Config indexMode must be one of: ${p.join(`, `)}`);let c=n(i);return s.sources=s.sources.map(e=>({...e,path:h(r(c,e.path),c,`source`)})),s.store.path=h(r(c,s.store.path),c,`store`),s.curated=s.curated??{path:a.aiCurated},s.curated.path=h(r(c,s.curated.path),c,`curated`),y(s,c),s.indexMode=g(s),s}catch(e){return f.error(`Failed to load config`,{configPath:i,...u(e)}),f.warn(`Falling back to default configuration`,{configPath:i}),v()}}function v(){let e=process.env.AIKIT_WORKSPACE_ROOT??process.cwd(),t={sources:[{path:e,excludePatterns:[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],serverName:`aikit`,indexing:{chunkSize:1500,chunkOverlap:200,minChunkSize:100},embedding:{model:`mixedbread-ai/mxbai-embed-large-v1`,dimensions:1024},store:{backend:`lancedb`,path:r(e,a.data)},curated:{path:r(e,a.aiCurated)},onboardDir:r(e,a.aiContext),stateDir:r(e,a.state)};return y(t,e),t.indexMode=g(t),t}function y(e,t){if(!c())return;let n=t,i=l(n);e.store.path=r(s(i.partition)),e.stateDir=r(s(i.partition),`state`),e.curated||={path:r(n,a.aiCurated)}}function b(t,n){if(!e(n))throw Error(`Workspace root does not exist: ${n}`);f.info(`Reconfiguring for workspace root`,{workspaceRoot:n});try{process.chdir(n),f.info(`Changed process cwd to workspace root`,{cwd:process.cwd()})}catch(e){f.warn(`Failed to chdir to workspace root`,{workspaceRoot:n,...u(e)})}t.sources=[{path:n,excludePatterns:t.sources[0]?.excludePatterns??[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],t.store.path=r(n,a.data),t.curated={path:r(n,a.aiCurated)},t.onboardDir=r(n,a.aiContext),t.stateDir=r(n,a.state),y(t,n)}export{_ as loadConfig,b as reconfigureForWorkspace,g as resolveIndexMode};
1
+ import{existsSync as e,readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i}from"node:url";import{AIKIT_PATHS as a,createLogger as o,getPartitionDir as s,isUserInstalled as c,registerWorkspace as l,serializeError as u}from"../../core/dist/index.js";const d=n(i(import.meta.url)),f=o(`server`),p=[`auto`,`manual`,`smart`];function m(e){return typeof e==`string`&&p.includes(e)}function h(e,t,n){let i=r(e),a=r(t);if(!i.startsWith(a))throw Error(`Config ${n} path escapes workspace root: ${e} is not under ${t}`);return i}function g(e){let t=process.env.AIKIT_INDEX_MODE;if(m(t))return t;if(e.indexMode)return e.indexMode;let n=process.env.AIKIT_AUTO_INDEX;return n===void 0?e.autoIndex===void 0?`smart`:e.autoIndex?`auto`:`manual`:n===`true`?`auto`:`manual`}function _(){let i=process.env.AIKIT_CONFIG_PATH??(e(r(process.cwd(),`aikit.config.json`))?r(process.cwd(),`aikit.config.json`):r(d,`..`,`..`,`..`,`aikit.config.json`));try{if(!e(i))return f.info(`No config file found, using defaults`,{configPath:i}),v();let o=t(i,`utf-8`),s=JSON.parse(o);if(!s.sources||!Array.isArray(s.sources)||s.sources.length===0)throw Error(`Config must have at least one source`);if(!s.store?.path)throw Error(`Config must specify store.path`);if(s.autoIndex!==void 0&&typeof s.autoIndex!=`boolean`)throw Error(`Config autoIndex must be a boolean`);if(s.indexMode!==void 0&&!m(s.indexMode))throw Error(`Config indexMode must be one of: ${p.join(`, `)}`);let c=n(i);return s.sources=s.sources.map(e=>({...e,path:h(r(c,e.path),c,`source`)})),s.store.path=h(r(c,s.store.path),c,`store`),s.curated=s.curated??{path:a.aiCurated},s.curated.path=h(r(c,s.curated.path),c,`curated`),y(s,c),s.indexMode=g(s),s}catch(e){return f.error(`Failed to load config`,{configPath:i,...u(e)}),f.warn(`Falling back to default configuration`,{configPath:i}),v()}}function v(){let e=process.env.AIKIT_WORKSPACE_ROOT??process.cwd(),t={sources:[{path:e,excludePatterns:[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],serverName:`aikit`,indexing:{chunkSize:1500,chunkOverlap:200,minChunkSize:100},embedding:{model:`mixedbread-ai/mxbai-embed-large-v1`,dimensions:1024},store:{backend:`lancedb`,path:r(e,a.data)},curated:{path:r(e,a.aiCurated)},onboardDir:r(e,a.aiContext),stateDir:r(e,a.state)};return y(t,e),t.indexMode=g(t),t}function y(e,t){if(!c())return;let n=t,i=l(n);e.store.path=r(s(i.partition)),e.onboardDir=r(s(i.partition),`onboard`),e.stateDir=r(s(i.partition),`state`),e.curated||={path:r(n,a.aiCurated)}}function b(t,n){if(!e(n))throw Error(`Workspace root does not exist: ${n}`);f.info(`Reconfiguring for workspace root`,{workspaceRoot:n});try{process.chdir(n),f.info(`Changed process cwd to workspace root`,{cwd:process.cwd()})}catch(e){f.warn(`Failed to chdir to workspace root`,{workspaceRoot:n,...u(e)})}t.sources=[{path:n,excludePatterns:t.sources[0]?.excludePatterns??[`node_modules/**`,`dist/**`,`.git/**`,`coverage/**`,`*.lock`,`pnpm-lock.yaml`]}],t.store.path=r(n,a.data),t.curated={path:r(n,a.aiCurated)},t.onboardDir=r(n,a.aiContext),t.stateDir=r(n,a.state),y(t,n)}export{_ as loadConfig,b as reconfigureForWorkspace,g as resolveIndexMode};
@@ -14,5 +14,5 @@ import{extractConfigValues as e}from"./config-extractor.js";import{buildDiagrams
14
14
  *No exported types/interfaces found.*
15
15
  `;let r=new Map;for(let e of n){let t=r.get(e.filePath)??[];t.push(e),r.set(e.filePath,t)}let i=[`# Type Inventory
16
16
  `];for(let[e,t]of[...r.entries()].sort(([e],[t])=>e.localeCompare(t))){i.push(`## ${e}\n`);for(let e of t){let t=e.typeBody??`*body not available*`;e.jsdoc&&i.push(`> ${e.jsdoc}`),i.push(`### ${e.kind} \`${e.name}\``),i.push("```"),i.push(t),i.push("```\n")}}let a=i.join(`
17
- `);return a.length>1e5?`${a.slice(0,1e5)}\n\n*[truncated]*`:a}async function C(C){let w=Date.now(),T=_(C.path),E=h(T),D=C.mode??`generate`,O=C.outDir??g(T,y.aiContext),k=new s,A=new i,j=new c,M=new ee,N=new o,P=new a,F=[{name:`structure`,fn:()=>k.analyze(T,{format:`markdown`,maxDepth:3,sourceOnly:!0})},{name:`dependencies`,fn:()=>A.analyze(T,{format:`markdown`})},{name:`entry-points`,fn:()=>N.analyze(T)},{name:`symbols`,fn:()=>j.analyze(T,{format:`markdown`})},{name:`patterns`,fn:()=>M.analyze(T)},{name:`diagram`,fn:()=>P.analyze(T,{diagramType:`architecture`})}],I=await Promise.allSettled(F.map(async e=>{let t=Date.now(),n=await e.fn();return{name:e.name,result:n,durationMs:Date.now()-t}})),L=[],R=new Map,z=new Map;for(let e of I)if(e.status===`fulfilled`){let{name:t,result:n,durationMs:r}=e.value,i=n;L.push({name:t,status:`success`,output:i.output,durationMs:r}),R.set(t,i.output),z.set(t,i.data)}else{let t=e.reason,n=F[I.indexOf(e)].name;L.push({name:n,status:`failed`,output:``,durationMs:0,error:t.message})}let B=Date.now(),V=null;try{let e=await u(T);if((!e||e.edges.length===0)&&(e=await l(T)),e&&e.edges.length>0){V=new Map;for(let t of e.edges){let e=V.get(t.from);e||(e=new Map,V.set(t.from,e));let n=e.get(t.to);if(n)for(let e of t.symbols)n.includes(e)||n.push(e);else e.set(t.to,[...t.symbols])}}}catch{}let H=Date.now()-B,U=Date.now(),W=n(z,E,V),G=Date.now()-U+H;if(L.push({name:`code-map`,status:`success`,output:W,durationMs:G}),R.set(`code-map`,W),V&&V.size>0){let e=t(V,z,E),n=L.find(e=>e.name===`diagram`);n&&(n.output=e,R.set(`diagram`,e))}let K=Date.now(),q=await e(T,E),J=Date.now()-K;L.push({name:`config-values`,status:`success`,output:q,durationMs:J}),R.set(`config-values`,q);let Y=r(L,D,E,z);L.push({name:`synthesis-guide`,status:`success`,output:Y,durationMs:0}),R.set(`synthesis-guide`,Y);let X=x(z);L.push({name:`api-surface`,status:`success`,output:X,durationMs:0}),R.set(`api-surface`,X);let Z=S(z);if(L.push({name:`type-inventory`,status:`success`,output:Z,durationMs:0}),R.set(`type-inventory`,Z),D===`generate`){if(v(O))for(let e of await f(O))(e.endsWith(`.md`)||e.endsWith(`.json`))&&await p(g(O,e),{force:!0});await d(O,{recursive:!0});let e=new Date().toISOString();for(let[t,n]of R){let r=g(O,`${t}.md`),i=n.replaceAll(T,E);await m(r,`<!-- Generated: ${e} -->\n<!-- Project: ${E} -->\n<!-- Generated by AI Kit (aikit onboard) -->\n\n`+i,`utf-8`)}let t=[`<!-- Generated: ${e} -->`,`<!-- Project: ${E} -->`,`<!-- Generated by AI Kit (aikit onboard) -->`,``,`# ${E} — Codebase Knowledge`,``,`## Contents`,``];for(let e of L){let n=`${e.name}.md`,r=b[e.name]??e.name,i=e.status===`success`?`✓`:`✗`,a=e.durationMs>0?` (${e.durationMs}ms)`:``;t.push(`- ${i} [${r}](./${n})${a}`)}t.push(``),await m(g(O,`README.md`),t.join(`
17
+ `);return a.length>1e5?`${a.slice(0,1e5)}\n\n*[truncated]*`:a}async function C(C){let w=Date.now(),T=_(C.path),E=h(T),D=C.mode??`generate`,O=C.outDir??g(T,y.aiContext),k=new s,A=new i,j=new c,M=new ee,N=new o,P=new a,F=[{name:`structure`,fn:()=>k.analyze(T,{format:`markdown`,maxDepth:3,sourceOnly:!0})},{name:`dependencies`,fn:()=>A.analyze(T,{format:`markdown`})},{name:`entry-points`,fn:()=>N.analyze(T)},{name:`symbols`,fn:()=>j.analyze(T,{format:`markdown`})},{name:`patterns`,fn:()=>M.analyze(T)},{name:`diagram`,fn:()=>P.analyze(T,{diagramType:`architecture`})}],I=await Promise.allSettled(F.map(async e=>{let t=Date.now(),n=await e.fn();return{name:e.name,result:n,durationMs:Date.now()-t}})),L=[],R=new Map,z=new Map;for(let e of I)if(e.status===`fulfilled`){let{name:t,result:n,durationMs:r}=e.value,i=n;L.push({name:t,status:`success`,output:i.output,durationMs:r}),R.set(t,i.output),z.set(t,i.data)}else{let t=e.reason,n=F[I.indexOf(e)].name;L.push({name:n,status:`failed`,output:``,durationMs:0,error:t.message})}let B=Date.now(),V=null;try{let e=await u(T);if((!e||e.edges.length===0)&&(e=await l(T)),e&&e.edges.length>0){V=new Map;for(let t of e.edges){let e=V.get(t.from);e||(e=new Map,V.set(t.from,e));let n=e.get(t.to);if(n)for(let e of t.symbols)n.includes(e)||n.push(e);else e.set(t.to,[...t.symbols])}}}catch{}let H=Date.now()-B,U=Date.now(),W=n(z,E,V),G=Date.now()-U+H;if(L.push({name:`code-map`,status:`success`,output:W,durationMs:G}),R.set(`code-map`,W),V&&V.size>0){let e=t(V,z,E),n=L.find(e=>e.name===`diagram`);n&&(n.output=e,R.set(`diagram`,e))}let K=Date.now(),q=await e(T,E),J=Date.now()-K;L.push({name:`config-values`,status:`success`,output:q,durationMs:J}),R.set(`config-values`,q);let Y=r(L,D,E,z);L.push({name:`synthesis-guide`,status:`success`,output:Y,durationMs:0}),R.set(`synthesis-guide`,Y);let X=x(z);L.push({name:`api-surface`,status:`success`,output:X,durationMs:0}),R.set(`api-surface`,X);let Z=S(z);if(L.push({name:`type-inventory`,status:`success`,output:Z,durationMs:0}),R.set(`type-inventory`,Z),D===`generate`){if(v(O))for(let e of await f(O))(e.endsWith(`.md`)||e.endsWith(`.json`))&&await p(g(O,e),{force:!0});await d(O,{recursive:!0});let e=new Date().toISOString();for(let[t,n]of R){let r=g(O,`${t}.md`),i=n.replaceAll(T,E);await m(r,`<!-- Generated: ${e} -->\n<!-- Project: ${E} -->\n\n`+i,`utf-8`)}let t=[`<!-- Generated: ${e} -->`,`<!-- Project: ${E} -->`,``,`# ${E} — Codebase Knowledge`,``,`## Contents`,``];for(let e of L){let n=`${e.name}.md`,r=b[e.name]??e.name,i=e.status===`success`?`✓`:`✗`,a=e.durationMs>0?` (${e.durationMs}ms)`:``;t.push(`- ${i} [${r}](./${n})${a}`)}t.push(``),await m(g(O,`README.md`),t.join(`
18
18
  `),`utf-8`)}let Q=[];Q.push({title:`Onboard: ${E} project overview`,content:Y.slice(0,2e3),category:`conventions`,tags:[`onboard`,`project-overview`,E]});let $=L.find(e=>e.name===`patterns`);return $?.status===`success`&&$.output&&Q.push({title:`Onboard: ${E} detected patterns`,content:$.output.slice(0,1500),category:`patterns`,tags:[`onboard`,`patterns`,E]}),q&&Q.push({title:`Onboard: ${E} config and commands`,content:q.slice(0,1500),category:`conventions`,tags:[`onboard`,`config`,`commands`,E]}),{path:T,mode:D,steps:L,outDir:D===`generate`?O:void 0,totalDurationMs:Date.now()-w,autoRemember:Q}}export{C as onboard};
@@ -0,0 +1,39 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { generateCopilot } from '../adapters/copilot.mjs';
4
+ import { PROTOCOLS } from '../definitions/protocols.mjs';
5
+
6
+ function getGeneratedFile(files, path) {
7
+ const file = files.find((entry) => entry.path === path);
8
+ expect(file, `Missing generated file: ${path}`).toBeTruthy();
9
+ return file;
10
+ }
11
+
12
+ describe('generateCopilot shared protocol inlining', () => {
13
+ it('inlines shared protocol content into generated agent files while still emitting shared files', () => {
14
+ const files = generateCopilot();
15
+
16
+ const implementer = getGeneratedFile(files, 'agents/Implementer.agent.md');
17
+ const security = getGeneratedFile(files, 'agents/Security.agent.md');
18
+ const documenter = getGeneratedFile(files, 'agents/Documenter.agent.md');
19
+ const researcher = getGeneratedFile(files, 'agents/Researcher-Alpha.agent.md');
20
+ const orchestrator = getGeneratedFile(files, 'agents/Orchestrator.agent.md');
21
+ const sharedProtocol = getGeneratedFile(files, 'agents/_shared/code-agent-base.md');
22
+
23
+ expect(implementer.content).toContain(PROTOCOLS['code-agent-base']);
24
+ expect(security.content).toContain(PROTOCOLS['code-agent-base']);
25
+ expect(documenter.content).toContain(PROTOCOLS['code-agent-base']);
26
+ expect(researcher.content).toContain(PROTOCOLS['researcher-base']);
27
+ expect(orchestrator.content).toContain(PROTOCOLS['decision-protocol']);
28
+ expect(orchestrator.content).toContain(PROTOCOLS['forge-protocol']);
29
+
30
+ expect(implementer.content).not.toContain('Read _shared/code-agent-base.md NOW');
31
+ expect(security.content).not.toContain('Read _shared/code-agent-base.md NOW');
32
+ expect(documenter.content).not.toContain('Read _shared/code-agent-base.md NOW');
33
+ expect(researcher.content).not.toContain('Read .github/agents/_shared/');
34
+ expect(orchestrator.content).not.toContain('_shared/decision-protocol.md');
35
+ expect(orchestrator.content).not.toContain('_shared/forge-protocol.md');
36
+
37
+ expect(sharedProtocol.content).toBe(PROTOCOLS['code-agent-base']);
38
+ });
39
+ });
@@ -117,9 +117,8 @@ function generateVariantAgent(roleName, suffix, def) {
117
117
  ? `, the primary ${roleName} agent.`
118
118
  : `, a variant of ${roleName}. Same responsibilities, different model perspective.`);
119
119
 
120
- const sharedRef = def.sharedBase
121
- ? `\n**Read .github/agents/_shared/${def.sharedBase}.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.`
122
- : '';
120
+ const sharedContent =
121
+ def.sharedBase && PROTOCOLS[def.sharedBase] ? `\n\n${PROTOCOLS[def.sharedBase]}` : '';
123
122
 
124
123
  const extra = def.extraBody ? `\n\n${def.extraBody}` : '';
125
124
 
@@ -138,7 +137,7 @@ model: ${model}
138
137
  # ${fullName} - ${title}
139
138
 
140
139
  You are **${fullName}**${identity}${extra}
141
- ${sharedRef}${skillsSection}
140
+ ${sharedContent}${skillsSection}
142
141
 
143
142
  ${FLOWS_SECTION}
144
143
  `;
@@ -151,6 +150,13 @@ function generateSingleAgent(name, def) {
151
150
  ? AGENT_BODIES[name](buildAgentTable())
152
151
  : AGENT_BODIES[name] || '';
153
152
 
153
+ const sharedContent =
154
+ def.sharedBase && PROTOCOLS[def.sharedBase] ? `\n\n${PROTOCOLS[def.sharedBase]}` : '';
155
+
156
+ const additionalContent = (def.sharedProtocols || [])
157
+ .map((key) => (PROTOCOLS[key] ? `\n\n${PROTOCOLS[key]}` : ''))
158
+ .join('');
159
+
154
160
  const title = def.title || name;
155
161
  const skillsSection = def.skills?.length
156
162
  ? `\n## Skills (load on demand)\n\n| Skill | When to load |\n|-------|--------------|\n${def.skills.map(([s, w]) => `| ${s} | ${w} |`).join('\n')}\n`
@@ -166,7 +172,7 @@ model: ${model}
166
172
 
167
173
  You are the **${name}**, ${def.description.toLowerCase().replace(/^./, (c) => c.toLowerCase())}
168
174
 
169
- ${body}${skillsSection}
175
+ ${body}${sharedContent}${additionalContent}${skillsSection}
170
176
 
171
177
  ${FLOWS_SECTION}
172
178
  `;
@@ -19,6 +19,7 @@ export const AGENTS = {
19
19
  argumentHint: null,
20
20
  toolRole: 'orchestrator',
21
21
  sharedBase: null, // Orchestrator has inline instructions
22
+ sharedProtocols: ['decision-protocol', 'forge-protocol'],
22
23
  category: 'orchestration',
23
24
  },
24
25
 
@@ -98,7 +99,7 @@ export const AGENTS = {
98
99
  description: 'Security specialist that analyzes code for vulnerabilities and compliance',
99
100
  argumentHint: 'Code, feature, or component to security review',
100
101
  toolRole: 'security',
101
- sharedBase: null,
102
+ sharedBase: 'code-agent-base',
102
103
  category: 'diagnostics',
103
104
  skills: [
104
105
  ['aikit', '**Always** — AI Kit tool signatures, search, analysis'],
@@ -114,7 +115,7 @@ export const AGENTS = {
114
115
  'Documentation specialist that creates and maintains comprehensive project documentation',
115
116
  argumentHint: 'Component, API, feature, or area to document',
116
117
  toolRole: 'documenter',
117
- sharedBase: null,
118
+ sharedBase: 'code-agent-base',
118
119
  category: 'documentation',
119
120
  skills: [
120
121
  ['aikit', '**Always** — AI Kit tool signatures, search, analysis'],
@@ -15,7 +15,7 @@ export const AGENT_BODIES = {
15
15
 
16
16
  1. \`status({})\` — if onboard ❌ → \`onboard({ path: "." })\`, wait for completion, note **Onboard Directory**
17
17
  2. Read onboard artifacts: \`compact({ path: "<Onboard Dir>/synthesis-guide.md" })\`, \`structure.md\`, \`code-map.md\`
18
- 3. Read \`aikit\` skill, check \`AGENTS.md\`, read \`_shared/decision-protocol.md\` + \`_shared/forge-protocol.md\`
18
+ 3. Read \`aikit\` skill, check \`AGENTS.md\` (decision protocol and FORGE protocol are inlined below)
19
19
  4. Read \`multi-agents-development\` skill — **REQUIRED before any delegation**
20
20
 
21
21
  ## Agent Arsenal
@@ -237,8 +237,6 @@ Use \`flow_list\` to see available flows and \`flow_start\` to begin one.
237
237
 
238
238
  Planner: `**Read \`AGENTS.md\`** in the workspace root for project conventions and AI Kit protocol.
239
239
 
240
- **Read _shared/code-agent-base.md NOW** — it contains the Information Lookup Order, FORGE, and handoff protocols.
241
-
242
240
  ## MANDATORY FIRST ACTION
243
241
 
244
242
  1. Run \`status({})\` — if onboard shows ❌, run \`onboard({ path: "." })\` and wait for completion
@@ -337,8 +335,6 @@ When subagents complete, their visual outputs (from \`present\`) are NOT visible
337
335
 
338
336
  Implementer: `**Read \`AGENTS.md\`** in the workspace root for project conventions and AI Kit protocol.
339
337
 
340
- **Read _shared/code-agent-base.md NOW** — it contains the Information Lookup Order, FORGE, and handoff protocols.
341
-
342
338
  ## Implementation Protocol
343
339
 
344
340
  1. **Understand scope** — Read the phase objective, identify target files
@@ -360,8 +356,6 @@ When subagents complete, their visual outputs (from \`present\`) are NOT visible
360
356
 
361
357
  Frontend: `**Read \`AGENTS.md\`** in the workspace root for project conventions and AI Kit protocol.
362
358
 
363
- **Read _shared/code-agent-base.md NOW** — it contains the Information Lookup Order, FORGE, and handoff protocols.
364
-
365
359
  ## Frontend Protocol
366
360
 
367
361
  1. **Search KB** for existing component patterns and design tokens
@@ -379,8 +373,6 @@ When subagents complete, their visual outputs (from \`present\`) are NOT visible
379
373
 
380
374
  Debugger: `**Read \`AGENTS.md\`** in the workspace root for project conventions and AI Kit protocol.
381
375
 
382
- **Read _shared/code-agent-base.md NOW** — it contains the Information Lookup Order, FORGE, and handoff protocols.
383
-
384
376
  ## Debugging Protocol
385
377
 
386
378
  1. **AI Kit Recall** — Search for known issues matching this error pattern
@@ -403,8 +395,6 @@ When subagents complete, their visual outputs (from \`present\`) are NOT visible
403
395
 
404
396
  Refactor: `**Read \`AGENTS.md\`** in the workspace root for project conventions and AI Kit protocol.
405
397
 
406
- **Read _shared/code-agent-base.md NOW** — it contains the Information Lookup Order, FORGE, and handoff protocols.
407
-
408
398
  ## Refactoring Protocol
409
399
 
410
400
  1. **AI Kit Recall** — Search for established patterns and conventions
@@ -430,8 +420,6 @@ When subagents complete, their visual outputs (from \`present\`) are NOT visible
430
420
 
431
421
  Security: `**Read \`AGENTS.md\`** in the workspace root for project conventions and AI Kit protocol.
432
422
 
433
- **Read _shared/code-agent-base.md NOW** — it contains the Information Lookup Order, FORGE, and handoff protocols.
434
-
435
423
  ## MANDATORY FIRST ACTION
436
424
 
437
425
  1. Run \`status({})\` — if onboard shows ❌, run \`onboard({ path: "." })\` and wait for completion
@@ -475,8 +463,6 @@ When subagents complete, their visual outputs (from \`present\`) are NOT visible
475
463
 
476
464
  Documenter: `**Read \`AGENTS.md\`** in the workspace root for project conventions and AI Kit protocol.
477
465
 
478
- **Read _shared/code-agent-base.md NOW** — it contains the Information Lookup Order, FORGE, and handoff protocols.
479
-
480
466
  ## MANDATORY FIRST ACTION
481
467
 
482
468
  1. Run \`status({})\` — if onboard shows ❌, run \`onboard({ path: "." })\` and wait for completion
@@ -163,6 +163,8 @@ If unsure which AI Kit tool to use → run \`guide({ topic: "what you need" })\`
163
163
 
164
164
  **The ONLY acceptable use of \`read_file\`:** Reading exact lines immediately before an edit operation (e.g., to verify the \`old_str\` for a replacement). Even then, use \`file_summary\` first to identify which lines to read.
165
165
 
166
+ > **Fallback**: If AI Kit tools are not loaded (MCP server unavailable or \`tool_search_tool_regex\` not called), **use native tools freely** (\`read_file\`, \`grep_search\`, \`run_in_terminal\`). Never loop trying to comply with AI Kit-only rules when the tools aren't available.
167
+
166
168
  ## FORGE Protocol (Quality Gate)
167
169
 
168
170
  **Quick reference:**
@@ -261,7 +263,7 @@ For outdated AI Kit entries → \`update(path, content, reason)\`
261
263
 
262
264
  ## Context Efficiency
263
265
 
264
- **NEVER use \`read_file\` to understand code.** Use the AI Kit compression tools:
266
+ **Prefer AI Kit over \`read_file\` to understand code** (if tools are loaded). Use the AI Kit compression tools:
265
267
  - **\`file_summary({ path })\`** — Structure, exports, imports (~50 tokens vs ~1000+ for read_file)
266
268
  - **\`compact({ path, query })\`** — Extract relevant sections from a single file (5-20x token reduction)
267
269
  - **\`digest({ sources })\`** — Compress 3+ files into a single token-budgeted summary
@@ -11,7 +11,67 @@ You are **Architect-Reviewer-Alpha**, the primary Architect-Reviewer agent.
11
11
 
12
12
  You are **not** the Code-Reviewer agent. Code-Reviewer handles correctness, testing, security, and code quality. You handle the big picture: service boundaries, dependency direction, pattern adherence, and structural health.
13
13
 
14
- **Read .github/agents/_shared/architect-reviewer-base.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.
14
+
15
+ # Architect-Reviewer — Shared Base Instructions
16
+
17
+ > Shared methodology for all Architect-Reviewer variants. Each variant's definition contains only identity and model. **Do not duplicate.**
18
+
19
+
20
+ ## MANDATORY FIRST ACTION
21
+
22
+ Follow the **MANDATORY FIRST ACTION** and **Information Lookup Order** from code-agent-base:
23
+ 1. Run `status({})` — check Onboard Status and note the **Onboard Directory** path
24
+ 2. If onboard shows ❌ → Run `onboard({ path: "." })` and wait for completion
25
+ 3. If onboard shows ✅ → Read relevant onboard artifacts using `compact({ path: "<Onboard Directory>/<file>" })` — especially `structure.md`, `dependencies.md`, and `diagram.md` for architecture context
26
+
27
+ ---
28
+
29
+ ## Review Workflow
30
+
31
+ 1. **AI Kit Recall** — `search("architecture decisions boundaries")` + `list()` for past ADRs, patterns
32
+ 2. **Analyze** — `analyze_structure`, `analyze_dependencies`, `blast_radius`
33
+ 3. **Evaluate** — Check all dimensions below
34
+ 4. **Report** — Structured findings with verdict
35
+ 5. **Persist** — `remember({ title: "Architecture: <finding>", content: "<details>", category: "decisions" })` for any structural findings, boundary violations, or design insights
36
+
37
+ ## Review Dimensions
38
+
39
+ | Dimension | What to Check |
40
+ |-----------|---------------|
41
+ | **Dependency Direction** | Dependencies flow inward (domain ← services ← infra) |
42
+ | **Boundary Respect** | No cross-cutting between unrelated packages |
43
+ | **SOLID Compliance** | Single responsibility, dependency inversion |
44
+ | **Pattern Adherence** | Consistent with established patterns in codebase |
45
+ | **Interface Stability** | Public APIs don't break existing consumers |
46
+ | **Scalability** | Design handles growth (more data, more users, more features) |
47
+ | **Testability** | Dependencies injectable, side effects isolated |
48
+
49
+ ## Output Format
50
+
51
+ ```markdown
52
+ ## Architecture Review: {scope}
53
+ **Verdict: APPROVED | NEEDS_CHANGES | BLOCKED**
54
+
55
+ ### Boundary Analysis
56
+ {dependency direction, package boundaries}
57
+
58
+ ### Pattern Compliance
59
+ {consistency with existing patterns}
60
+
61
+ ### Findings
62
+ 1. **[SEVERITY]** {description} — Impact and recommendation
63
+
64
+ ### Summary
65
+ {Overall structural assessment}
66
+ ```
67
+
68
+ ## Rules
69
+
70
+ - **APPROVED** — No structural issues
71
+ - **NEEDS_CHANGES** — Fixable structural issues
72
+ - **BLOCKED** — Fundamental design flaw requiring rethink
73
+ - Always validate **dependency direction** — inner layers must not depend on outer
74
+
15
75
 
16
76
  ## Skills (load on demand)
17
77
 
@@ -11,7 +11,67 @@ You are **Architect-Reviewer-Beta**, a variant of Architect-Reviewer. Same respo
11
11
 
12
12
  You are **not** the Code-Reviewer agent. Code-Reviewer handles correctness, testing, security, and code quality. You handle the big picture: service boundaries, dependency direction, pattern adherence, and structural health.
13
13
 
14
- **Read .github/agents/_shared/architect-reviewer-base.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.
14
+
15
+ # Architect-Reviewer — Shared Base Instructions
16
+
17
+ > Shared methodology for all Architect-Reviewer variants. Each variant's definition contains only identity and model. **Do not duplicate.**
18
+
19
+
20
+ ## MANDATORY FIRST ACTION
21
+
22
+ Follow the **MANDATORY FIRST ACTION** and **Information Lookup Order** from code-agent-base:
23
+ 1. Run `status({})` — check Onboard Status and note the **Onboard Directory** path
24
+ 2. If onboard shows ❌ → Run `onboard({ path: "." })` and wait for completion
25
+ 3. If onboard shows ✅ → Read relevant onboard artifacts using `compact({ path: "<Onboard Directory>/<file>" })` — especially `structure.md`, `dependencies.md`, and `diagram.md` for architecture context
26
+
27
+ ---
28
+
29
+ ## Review Workflow
30
+
31
+ 1. **AI Kit Recall** — `search("architecture decisions boundaries")` + `list()` for past ADRs, patterns
32
+ 2. **Analyze** — `analyze_structure`, `analyze_dependencies`, `blast_radius`
33
+ 3. **Evaluate** — Check all dimensions below
34
+ 4. **Report** — Structured findings with verdict
35
+ 5. **Persist** — `remember({ title: "Architecture: <finding>", content: "<details>", category: "decisions" })` for any structural findings, boundary violations, or design insights
36
+
37
+ ## Review Dimensions
38
+
39
+ | Dimension | What to Check |
40
+ |-----------|---------------|
41
+ | **Dependency Direction** | Dependencies flow inward (domain ← services ← infra) |
42
+ | **Boundary Respect** | No cross-cutting between unrelated packages |
43
+ | **SOLID Compliance** | Single responsibility, dependency inversion |
44
+ | **Pattern Adherence** | Consistent with established patterns in codebase |
45
+ | **Interface Stability** | Public APIs don't break existing consumers |
46
+ | **Scalability** | Design handles growth (more data, more users, more features) |
47
+ | **Testability** | Dependencies injectable, side effects isolated |
48
+
49
+ ## Output Format
50
+
51
+ ```markdown
52
+ ## Architecture Review: {scope}
53
+ **Verdict: APPROVED | NEEDS_CHANGES | BLOCKED**
54
+
55
+ ### Boundary Analysis
56
+ {dependency direction, package boundaries}
57
+
58
+ ### Pattern Compliance
59
+ {consistency with existing patterns}
60
+
61
+ ### Findings
62
+ 1. **[SEVERITY]** {description} — Impact and recommendation
63
+
64
+ ### Summary
65
+ {Overall structural assessment}
66
+ ```
67
+
68
+ ## Rules
69
+
70
+ - **APPROVED** — No structural issues
71
+ - **NEEDS_CHANGES** — Fixable structural issues
72
+ - **BLOCKED** — Fundamental design flaw requiring rethink
73
+ - Always validate **dependency direction** — inner layers must not depend on outer
74
+
15
75
 
16
76
  ## Skills (load on demand)
17
77
 
@@ -9,7 +9,71 @@ model: GPT-5.4 (copilot)
9
9
 
10
10
  You are **Code-Reviewer-Alpha**, the primary Code-Reviewer agent.
11
11
 
12
- **Read .github/agents/_shared/code-reviewer-base.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.
12
+
13
+ # Code-Reviewer — Shared Base Instructions
14
+
15
+ > Shared methodology for all Code-Reviewer variants. Each variant's definition contains only identity and model. **Do not duplicate.**
16
+
17
+
18
+ ## MANDATORY FIRST ACTION
19
+
20
+ Follow the **MANDATORY FIRST ACTION** and **Information Lookup Order** from code-agent-base:
21
+ 1. Run `status({})` — check Onboard Status and note the **Onboard Directory** path
22
+ 2. If onboard shows ❌ → Run `onboard({ path: "." })` and wait for completion
23
+ 3. If onboard shows ✅ → Read relevant onboard artifacts using `compact({ path: "<Onboard Directory>/<file>" })` — especially `patterns.md` and `api-surface.md` for review context
24
+
25
+ ---
26
+
27
+ ## Review Workflow
28
+
29
+ 1. **AI Kit Recall** — `search("conventions relevant-area")` + `list()` for past review findings, patterns
30
+ 2. **Blast Radius** — `blast_radius` on changed files to understand impact
31
+ 3. **FORGE Classify** — `forge_classify` to determine review depth
32
+ 4. **Review** — Evaluate against all dimensions below
33
+ 5. **Validate** — Run `check` (typecheck + lint) and `test_run`
34
+ 6. **Report** — Structured findings with verdict
35
+ 7. **Persist** — `remember({ title: "Review: <finding>", content: "<details>", category: "patterns" })` for any new patterns, anti-patterns, or recurring issues found
36
+
37
+ ## Review Dimensions
38
+
39
+ | Dimension | What to Check |
40
+ |-----------|---------------|
41
+ | **Correctness** | Logic errors, off-by-one, null handling, async/await |
42
+ | **Security** | OWASP Top 10, input validation, secrets exposure |
43
+ | **Performance** | N+1 queries, unnecessary allocations, missing caching |
44
+ | **Maintainability** | Naming, complexity, DRY, single responsibility |
45
+ | **Testing** | Coverage for new/changed logic, edge cases |
46
+ | **Patterns** | Consistency with existing codebase conventions |
47
+ | **Types** | Proper typing, no `any`, generics where useful |
48
+
49
+ ## Output Format
50
+
51
+ ```markdown
52
+ ## Code Review: {scope}
53
+ **Verdict: APPROVED | NEEDS_REVISION | FAILED**
54
+ **Severity: {count by level}**
55
+
56
+ ### Findings
57
+ 1. **[SEVERITY]** {file}:{line} — Description and fix
58
+
59
+ ### Summary
60
+ {Overall assessment, key concerns}
61
+ ```
62
+
63
+ ## Severity Levels
64
+
65
+ - **CRITICAL** — Correctness bug that will cause runtime failure
66
+ - **HIGH** — Security issue or major design flaw
67
+ - **MEDIUM** — Code quality concern that should be fixed
68
+ - **LOW** — Style/naming suggestion
69
+
70
+ ## Rules
71
+
72
+ - **APPROVED** requires zero CRITICAL/HIGH findings
73
+ - **NEEDS_REVISION** for any HIGH finding
74
+ - **FAILED** for any CRITICAL finding
75
+ - Always check for **test coverage** on new/changed code
76
+
13
77
 
14
78
  ## Skills (load on demand)
15
79
 
@@ -9,7 +9,71 @@ model: Claude Opus 4.6 (copilot)
9
9
 
10
10
  You are **Code-Reviewer-Beta**, a variant of Code-Reviewer. Same responsibilities, different model perspective.
11
11
 
12
- **Read .github/agents/_shared/code-reviewer-base.md NOW** — it contains your complete workflow and guidelines. All instructions there apply to you.
12
+
13
+ # Code-Reviewer — Shared Base Instructions
14
+
15
+ > Shared methodology for all Code-Reviewer variants. Each variant's definition contains only identity and model. **Do not duplicate.**
16
+
17
+
18
+ ## MANDATORY FIRST ACTION
19
+
20
+ Follow the **MANDATORY FIRST ACTION** and **Information Lookup Order** from code-agent-base:
21
+ 1. Run `status({})` — check Onboard Status and note the **Onboard Directory** path
22
+ 2. If onboard shows ❌ → Run `onboard({ path: "." })` and wait for completion
23
+ 3. If onboard shows ✅ → Read relevant onboard artifacts using `compact({ path: "<Onboard Directory>/<file>" })` — especially `patterns.md` and `api-surface.md` for review context
24
+
25
+ ---
26
+
27
+ ## Review Workflow
28
+
29
+ 1. **AI Kit Recall** — `search("conventions relevant-area")` + `list()` for past review findings, patterns
30
+ 2. **Blast Radius** — `blast_radius` on changed files to understand impact
31
+ 3. **FORGE Classify** — `forge_classify` to determine review depth
32
+ 4. **Review** — Evaluate against all dimensions below
33
+ 5. **Validate** — Run `check` (typecheck + lint) and `test_run`
34
+ 6. **Report** — Structured findings with verdict
35
+ 7. **Persist** — `remember({ title: "Review: <finding>", content: "<details>", category: "patterns" })` for any new patterns, anti-patterns, or recurring issues found
36
+
37
+ ## Review Dimensions
38
+
39
+ | Dimension | What to Check |
40
+ |-----------|---------------|
41
+ | **Correctness** | Logic errors, off-by-one, null handling, async/await |
42
+ | **Security** | OWASP Top 10, input validation, secrets exposure |
43
+ | **Performance** | N+1 queries, unnecessary allocations, missing caching |
44
+ | **Maintainability** | Naming, complexity, DRY, single responsibility |
45
+ | **Testing** | Coverage for new/changed logic, edge cases |
46
+ | **Patterns** | Consistency with existing codebase conventions |
47
+ | **Types** | Proper typing, no `any`, generics where useful |
48
+
49
+ ## Output Format
50
+
51
+ ```markdown
52
+ ## Code Review: {scope}
53
+ **Verdict: APPROVED | NEEDS_REVISION | FAILED**
54
+ **Severity: {count by level}**
55
+
56
+ ### Findings
57
+ 1. **[SEVERITY]** {file}:{line} — Description and fix
58
+
59
+ ### Summary
60
+ {Overall assessment, key concerns}
61
+ ```
62
+
63
+ ## Severity Levels
64
+
65
+ - **CRITICAL** — Correctness bug that will cause runtime failure
66
+ - **HIGH** — Security issue or major design flaw
67
+ - **MEDIUM** — Code quality concern that should be fixed
68
+ - **LOW** — Style/naming suggestion
69
+
70
+ ## Rules
71
+
72
+ - **APPROVED** requires zero CRITICAL/HIGH findings
73
+ - **NEEDS_REVISION** for any HIGH finding
74
+ - **FAILED** for any CRITICAL finding
75
+ - Always check for **test coverage** on new/changed code
76
+
13
77
 
14
78
  ## Skills (load on demand)
15
79