feat: add six specialized Claude agent definitions under .claude/agents for audit, devii, docs, dry, fanout, and frontend maintenance

This commit is contained in:
2026-06-13 18:34:47 +00:00
parent ede7a863b7
commit de745f7a75
107 changed files with 2611 additions and 517 deletions
+132
View File
@@ -0,0 +1,132 @@
// retoor <retoor@molodetz.nl>
export const meta = {
name: 'devii-tool',
description: 'Add a Devii agent capability: an Action in the catalog with auth flags matched to the route guard, dispatcher wiring, API docs, and a test, then verify role-gating and confirmation',
phases: [
{ title: 'Understand', detail: 'find the underlying route and a similar Action to mirror' },
{ title: 'Implement', detail: 'add the Action, wire the handler, document it' },
{ title: 'Verify', detail: 'role-gating, flag alignment, and confirm gating' },
{ title: 'Fix', detail: 'close gaps and write the action test' },
],
}
const RULES = [
'Obey DevPlace hard rules while editing:',
'- No comments or docstrings in source except the file header and the @tool docstring required for a tool schema. New files start with the "retoor <retoor@molodetz.nl>" header.',
'- No em-dash characters; use a hyphen. Full Python type hints; pathlib over os.',
'- A Devii Action requires_auth/requires_admin MUST exactly match the underlying route guard. Never grant a member an admin capability. A non-admin must not even see an admin tool schema.',
'- If the action is irreversible or destructive, add it to dispatcher CONFIRM_REQUIRED and declare a confirm boolean param in its spec (schemas set additionalProperties:false, so a gated tool without a declared confirm param can never receive confirm=true and loops forever).',
'- Prefer handler="http" reusing an existing REST route; only add a local controller handler when there is no route. Reuse the arg()/body()/query()/confirm() helpers for params.',
'- Validate with "python -m agents.validator ." and "python -c \\"from devplacepy.main import app\\"". NEVER run the test suite. Never perform any git write.',
].join('\n')
function toolBrief() {
if (!args) return ''
if (typeof args === 'string') return args
if (typeof args.description === 'string') return args.description
return JSON.stringify(args)
}
const ask = toolBrief()
if (!ask) {
log('No tool description provided. Invoke as /devii-tool <what the tool should do>.')
return { error: 'no description provided' }
}
const MAP_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary'],
properties: {
summary: { type: 'string' },
underlyingRoute: { type: 'string' },
routeGuard: { type: 'string' },
similarAction: { type: 'string' },
handler: { type: 'string' },
destructive: { type: 'boolean' },
},
}
const BUILD_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'filesChanged', 'validatorPassed'],
properties: {
summary: { type: 'string' },
actionName: { type: 'string' },
filesChanged: { type: 'array', items: { type: 'string' } },
validatorPassed: { type: 'boolean' },
importOk: { type: 'boolean' },
},
}
const FINDINGS_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'findings'],
properties: {
summary: { type: 'string' },
findings: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['severity', 'file', 'rule', 'message'],
properties: {
severity: { type: 'string', enum: ['error', 'warning', 'info'] },
file: { type: 'string' },
line: { type: 'integer' },
rule: { type: 'string' },
message: { type: 'string' },
},
},
},
},
}
log(`Devii tool: ${ask}`)
const map = await agent(
`Find the underlying REST route this Devii tool should call (or determine it needs a local controller handler), its exact auth guard, and the most similar existing Action in services/devii/actions/catalog.py to mirror. Note whether the action is destructive. Do not write anything.\n\nTool request: ${ask}`,
{ agentType: 'Explore', label: 'understand', phase: 'Understand', schema: MAP_SCHEMA }
)
const build = await agent(
`Add this Devii tool, editing files directly in the repo. Add the Action to the catalog mirroring the similar action, set requires_auth/requires_admin to exactly match the underlying route guard, wire the dispatcher handler if a new local handler is needed, and add a docs_api.py entry if it wraps an HTTP endpoint. If destructive, add it to CONFIRM_REQUIRED and declare a confirm param. Then run "python -m agents.validator ." and "python -c \\"from devplacepy.main import app\\"". Do not write the test here. Do not run the suite. Do not commit.\n\nTool request: ${ask}\n\nContext:\n${JSON.stringify(map, null, 2)}\n\n${RULES}\n\nReturn the action name, files changed, and whether validator and import passed.`,
{ label: 'implement', phase: 'Implement', schema: BUILD_SCHEMA }
)
const changed = (build && build.filesChanged) || []
const scopeNote = changed.length ? `\n\nRestrict findings to these files:\n${changed.join('\n')}` : ''
const audits = await parallel(
[
{ key: 'devii', agent: 'devii-maintainer' },
{ key: 'security', agent: 'security-maintainer' },
].map((a) => () =>
agent(
`Operate in REPORT mode (read-only). Audit the new Devii tool for your single dimension: confirm the auth flags match the route guard, no admin schema leaks to a non-admin, and any destructive action has both CONFIRM_REQUIRED membership and a declared confirm param.${scopeNote}\n\nTool request: ${ask}`,
{ agentType: a.agent, label: `verify:${a.key}`, phase: 'Verify', schema: FINDINGS_SCHEMA }
).then((r) => ({ key: a.key, findings: (r && r.findings) || [] }))
)
)
const gaps = audits
.filter(Boolean)
.flatMap((r) => r.findings.map((f) => ({ dimension: r.key, ...f })))
.filter((f) => f.severity !== 'info')
let gapFix = 'no actionable gaps'
if (gaps.length) {
gapFix = await agent(
`Close these Devii tool gaps with minimal root-cause fixes in the repo, then re-run "python -m agents.validator .". Do not run the suite. Do not commit.\n\nGaps:\n${JSON.stringify(gaps, null, 2)}\n\n${RULES}`,
{ label: 'fix-gaps', phase: 'Fix' }
)
}
const test = await agent(
`Operate in FIX mode. Write the integration test for this Devii tool following the required patterns (tests/api/devii layout). Validate by a clean import only. NEVER run the suite.\n\nTool request: ${ask}\nAction: ${build && build.actionName}\nFiles changed:\n${changed.join('\n')}`,
{ agentType: 'test-maintainer', label: 'test', phase: 'Fix' }
)
return { ask, map, build, audit: gaps, gapFix, test }
+139
View File
@@ -0,0 +1,139 @@
// retoor <retoor@molodetz.nl>
export const meta = {
name: 'endpoint',
description: 'Scaffold ONE new DevPlace route across all of its touchpoints (Form model, Out schema, guarded handler with respond, main.py mount, template, Devii action, API docs, SEO, test) and verify it',
phases: [
{ title: 'Understand', detail: 'find the closest existing route to mirror' },
{ title: 'Implement', detail: 'wire the route across every touchpoint' },
{ title: 'Verify', detail: 'completeness and security review of the new route' },
{ title: 'Fix', detail: 'close gaps and write the route test' },
],
}
const RULES = [
'Obey DevPlace hard rules while editing:',
'- No comments or docstrings in source (except the file header and @tool docstrings). New files start with the "retoor <retoor@molodetz.nl>" header in the language comment style.',
'- No em-dash characters; use a hyphen. Full Python type hints; pathlib over os; Pydantic Form input with explicit max lengths; sanitize and bound user input.',
'- Reuse templating.templates, database.py batch helpers, respond(), the shared partials and frontend utilities. Never per-router Jinja2Templates.',
'- Guards: get_current_user (public read), require_user (member write), require_admin (admin). Every POST/PUT/DELETE is guarded. Declare specific routes before catch-alls. Never pass a respond() context key that collides with a Jinja global (use viewer_is_admin).',
'- Validate with "python -m agents.validator ." and "python -c \\"from devplacepy.main import app\\"". NEVER run the test suite. Never perform any git write.',
].join('\n')
const TOUCHPOINTS = [
'A single DevPlace route must be wired across these touchpoints, all in agreement:',
'1. models.py - a Form model for the input (data: Annotated[SomeForm, Form()]) with max lengths, if it takes a body.',
'2. schemas.py - a *Out(_Out) model carrying every key the JSON response returns.',
'3. database.py - any query/batch helper it needs (no inline N+1); indexes in init_db() if it queries a new column.',
'4. routers/{area}.py - the handler with the correct guard, returning respond(request, template, ctx, model=XOut); register the router in main.py with its prefix if new.',
'5. templates/ + static/css + static/js - the view if it renders HTML.',
'6. services/devii/actions/catalog.py - an Action whose method/path/requires_auth/requires_admin match the route guard, if a user could ask Devii to do it; confirm param + CONFIRM_REQUIRED if destructive.',
'7. docs_api.py - an endpoint() entry with params and sample_response.',
'8. seo.py - base_seo_context for a public page; sitemap entry if indexable.',
].join('\n')
function endpointBrief() {
if (!args) return ''
if (typeof args === 'string') return args
if (typeof args.description === 'string') return args.description
return JSON.stringify(args)
}
const ask = endpointBrief()
if (!ask) {
log('No endpoint description provided. Invoke as /endpoint <method path - purpose>.')
return { error: 'no description provided' }
}
const MAP_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary'],
properties: {
summary: { type: 'string' },
similarRoute: { type: 'string' },
files: { type: 'array', items: { type: 'string' } },
},
}
const BUILD_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'filesChanged', 'validatorPassed'],
properties: {
summary: { type: 'string' },
filesChanged: { type: 'array', items: { type: 'string' } },
validatorPassed: { type: 'boolean' },
importOk: { type: 'boolean' },
},
}
const FINDINGS_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'findings'],
properties: {
summary: { type: 'string' },
findings: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['severity', 'file', 'rule', 'message'],
properties: {
severity: { type: 'string', enum: ['error', 'warning', 'info'] },
file: { type: 'string' },
line: { type: 'integer' },
rule: { type: 'string' },
message: { type: 'string' },
},
},
},
},
}
log(`Endpoint: ${ask}`)
const map = await agent(
`Find the closest existing DevPlace route to mirror for this new endpoint, and read it end to end (handler, schema, docs entry, Devii action, test). Do not write anything.\n\nEndpoint: ${ask}\n\n${TOUCHPOINTS}`,
{ agentType: 'Explore', label: 'understand', phase: 'Understand', schema: MAP_SCHEMA }
)
const build = await agent(
`Implement this single DevPlace route across every applicable touchpoint, editing files directly in the repo, mirroring the closest existing route. Keep the layers in agreement (Out schema carries every returned JSON key; Devii action auth flags match the guard). Then run "python -m agents.validator ." and "python -c \\"from devplacepy.main import app\\"". Do not write the test here. Do not run the suite. Do not commit.\n\nEndpoint: ${ask}\n\nClosest route to mirror:\n${JSON.stringify(map, null, 2)}\n\n${TOUCHPOINTS}\n\n${RULES}\n\nReturn the files changed and whether validator and import passed.`,
{ label: 'implement', phase: 'Implement', schema: BUILD_SCHEMA }
)
const changed = (build && build.filesChanged) || []
const scopeNote = changed.length ? `\n\nRestrict findings to these files:\n${changed.join('\n')}` : ''
const audits = await parallel(
[
{ key: 'fanout', agent: 'fanout-maintainer' },
{ key: 'security', agent: 'security-maintainer' },
].map((a) => () =>
agent(
`Operate in REPORT mode (read-only). Audit the new route for your single dimension.${scopeNote}\n\nEndpoint: ${ask}`,
{ agentType: a.agent, label: `verify:${a.key}`, phase: 'Verify', schema: FINDINGS_SCHEMA }
).then((r) => ({ key: a.key, findings: (r && r.findings) || [] }))
)
)
const gaps = audits
.filter(Boolean)
.flatMap((r) => r.findings.map((f) => ({ dimension: r.key, ...f })))
.filter((f) => f.severity !== 'info')
let gapFix = 'no actionable gaps'
if (gaps.length) {
gapFix = await agent(
`Close these gaps on the new route with minimal root-cause fixes in the repo, then re-run "python -m agents.validator .". Do not run the suite. Do not commit.\n\nGaps:\n${JSON.stringify(gaps, null, 2)}\n\n${RULES}`,
{ label: 'fix-gaps', phase: 'Fix' }
)
}
const test = await agent(
`Operate in FIX mode. Write the integration test for this new route following the required patterns and the directory-mirrors-path layout. Validate by a clean import only. NEVER run the suite.\n\nEndpoint: ${ask}\nFiles changed:\n${changed.join('\n')}`,
{ agentType: 'test-maintainer', label: 'test', phase: 'Fix' }
)
return { ask, map, build, audit: gaps, gapFix, test }
+182
View File
@@ -0,0 +1,182 @@
// retoor <retoor@molodetz.nl>
export const meta = {
name: 'feature',
description: 'Add a feature across the full DevPlace fan-out: understand the area, plan the layers, implement coherently in the repo, audit completeness and security, fix gaps and write tests, then verify',
phases: [
{ title: 'Understand', detail: 'map the target area and a similar existing feature' },
{ title: 'Plan', detail: 'a per-layer implementation plan across the nine touchpoints' },
{ title: 'Implement', detail: 'build all layers coherently in the repo' },
{ title: 'Audit', detail: 'completeness and security review of the changed files' },
{ title: 'Fix', detail: 'close audit gaps and write missing integration tests' },
],
}
const RULES = [
'Obey DevPlace hard rules while editing:',
'- No comments or docstrings in source (except the mandatory file header and @tool docstrings).',
'- First line of any NEW file is the header: Python "# retoor <retoor@molodetz.nl>", JS "// retoor <retoor@molodetz.nl>", CSS "/* retoor <retoor@molodetz.nl> */".',
'- No em-dash characters; use a hyphen. Source is English only.',
'- Full type hints on Python signatures and variables; pathlib over os; Pydantic Form input with explicit max lengths; sanitize and bound all user input.',
'- Reuse shared helpers: templating.templates (never a per-router Jinja2Templates), database.py batch helpers (no inline N+1), the respond() negotiator, _avatar_link.html / _user_link.html, and on the frontend Http / Poller / JobPoller / OptimisticAction / FloatingWindow.',
'- Auth guards: get_current_user (public read), require_user (member write), require_admin (admin). Every POST/PUT/DELETE is guarded; deletes are soft and owner-or-admin.',
'- Never pass a respond() context key that collides with a Jinja global (use viewer_is_admin, not is_admin). Dates are DD/MM/YYYY via format_date.',
'- Validate with "python -m agents.validator ." and "python -c \\"from devplacepy.main import app\\"". NEVER run the test suite. Never perform any git write.',
].join('\n')
const FANOUT = [
'The DevPlace feature fan-out (one route serves all of these; keep them in agreement):',
'1. models.py - a Pydantic Form model: data: Annotated[SomeForm, Form()], fields with max lengths.',
'2. schemas.py - a *Out(_Out) model with every key the JSON response returns (a key absent from *Out is silently dropped).',
'3. database.py - query/batch helpers (no inline N+1); indexes in init_db() with CREATE INDEX IF NOT EXISTS; soft-delete columns (deleted_at/deleted_by) on any new table.',
'4. routers/{area}.py - handler with the right guard; return respond(request, template, ctx, model=XOut); declare specific routes before catch-alls; register the router in main.py with its prefix.',
'5. templates/ + static/css + static/js - extend base.html; page CSS in extra_head, page JS in extra_js; ES6 one class per module reachable on app; reuse partials and design tokens; responsive to small phones.',
'6. services/devii/actions/catalog.py - an Action(name, method, path, summary, params, requires_auth, requires_admin) if a user could ask Devii to do it; a confirm param plus membership in CONFIRM_REQUIRED if destructive.',
'7. docs_api.py - an endpoint() entry in the right group with params and sample_response for every public or authenticated route.',
'8. seo.py - base_seo_context(request, ...) merged into the context for public pages; a sitemap entry in routers/seo.py if indexable.',
'9. README.md (product) + AGENTS.md (mechanics) + CLAUDE.md (only for a genuinely new architectural rule).',
].join('\n')
function featureBrief() {
if (!args) return ''
if (typeof args === 'string') return args
if (typeof args.description === 'string') return args.description
if (typeof args.brief === 'string') return args.brief
return JSON.stringify(args)
}
const ask = featureBrief()
if (!ask) {
log('No feature description provided. Invoke as /feature <what to build>.')
return { error: 'no description provided' }
}
const MAP_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'files'],
properties: {
summary: { type: 'string' },
area: { type: 'string' },
files: { type: 'array', items: { type: 'string' } },
similarFeature: { type: 'string' },
notes: { type: 'string' },
},
}
const PLAN_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['steps'],
properties: {
steps: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['layer', 'file', 'change'],
properties: {
layer: { type: 'string' },
file: { type: 'string' },
change: { type: 'string' },
},
},
},
outOfScope: { type: 'array', items: { type: 'string' } },
},
}
const BUILD_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'filesChanged', 'validatorPassed'],
properties: {
summary: { type: 'string' },
filesChanged: { type: 'array', items: { type: 'string' } },
validatorPassed: { type: 'boolean' },
importOk: { type: 'boolean' },
notes: { type: 'string' },
},
}
const FINDINGS_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'findings'],
properties: {
summary: { type: 'string' },
findings: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['severity', 'file', 'rule', 'message'],
properties: {
severity: { type: 'string', enum: ['error', 'warning', 'info'] },
file: { type: 'string' },
line: { type: 'integer' },
rule: { type: 'string' },
message: { type: 'string' },
},
},
},
},
}
log(`Feature: ${ask}`)
const map = await agent(
`Map the area of the DevPlace codebase relevant to this feature request, so it can be implemented. Read the closest existing feature end to end (its router, template, tests, and AGENTS.md section) as the pattern to follow. Do not write anything.\n\nFeature request: ${ask}\n\n${FANOUT}\n\nReturn: a summary of how this should be built, the concrete files to touch or create, the most similar existing feature to mirror, and any constraints.`,
{ agentType: 'Explore', label: 'understand', phase: 'Understand', schema: MAP_SCHEMA }
)
const plan = await agent(
`Produce a precise, per-layer implementation plan for this DevPlace feature. One step per file with the exact touchpoint to add or change. Mark layers that are intentionally not needed as outOfScope with a reason. Do not write code.\n\nFeature request: ${ask}\n\nArea map:\n${JSON.stringify(map, null, 2)}\n\n${FANOUT}`,
{ agentType: 'Plan', label: 'plan', phase: 'Plan', schema: PLAN_SCHEMA }
)
const build = await agent(
`Implement this DevPlace feature coherently and completely, editing files directly in the repo. Follow the plan; keep every layer in agreement (the *Out schema must carry every JSON key the handler returns; the Devii action auth flags must match the route guard). When done, run "python -m agents.validator ." and "python -c \\"from devplacepy.main import app\\"" and report whether each passed. Do not write tests in this step. Do not run the test suite. Do not commit.\n\nFeature request: ${ask}\n\nPlan:\n${JSON.stringify(plan, null, 2)}\n\n${FANOUT}\n\n${RULES}\n\nReturn the list of files you changed or created, whether the validator and the import passed, and a short summary.`,
{ label: 'implement', phase: 'Implement', schema: BUILD_SCHEMA }
)
const changed = (build && build.filesChanged) || []
const scopeNote = changed.length
? `\n\nRestrict your findings to these changed files (read others only for cross-reference):\n${changed.join('\n')}`
: ''
const AUDITORS = [
{ key: 'fanout', agent: 'fanout-maintainer' },
{ key: 'security', agent: 'security-maintainer' },
{ key: 'docs', agent: 'docs-maintainer' },
]
const audits = await parallel(
AUDITORS.map((a) => () =>
agent(
`Operate in REPORT mode (read-only). Audit the just-implemented feature for your single dimension. Confirm each finding against the source.${scopeNote}\n\nFeature request: ${ask}`,
{ agentType: a.agent, label: `audit:${a.key}`, phase: 'Audit', schema: FINDINGS_SCHEMA }
).then((r) => ({ key: a.key, findings: (r && r.findings) || [] }))
)
)
const gaps = audits
.filter(Boolean)
.flatMap((r) => r.findings.map((f) => ({ dimension: r.key, ...f })))
.filter((f) => f.severity !== 'info')
let gapFix = 'no actionable gaps from the audit'
if (gaps.length) {
gapFix = await agent(
`Close these completeness and security gaps found by the audit of the new feature. Apply minimal root-cause fixes directly in the repo, keeping all layers in agreement. Re-run "python -m agents.validator ." afterward. Do not run the test suite. Do not commit.\n\nGaps:\n${JSON.stringify(gaps, null, 2)}\n\n${RULES}`,
{ label: 'fix-gaps', phase: 'Fix' }
)
}
const tests = await agent(
`Operate in FIX mode. Write the missing integration tests for this new feature following the required Playwright patterns and the directory-mirrors-path layout. Validate each new test module by a clean import only. NEVER run the suite, not the full suite and not one file.\n\nFeature request: ${ask}\nFiles changed:\n${changed.join('\n')}`,
{ agentType: 'test-maintainer', label: 'tests', phase: 'Fix' }
)
log(`Feature build complete: ${changed.length} file(s), ${gaps.length} audit gap(s) addressed`)
return { ask, map, plan, build, audit: gaps, gapFix, tests }
+140
View File
@@ -0,0 +1,140 @@
// retoor <retoor@molodetz.nl>
export const meta = {
name: 'fleet',
description: 'DevPlace maintenance fleet: 10 dimension subagents scan in parallel, then every finding is adversarially verified against source before it is reported',
phases: [
{ title: 'Review', detail: '10 dimension subagents scan devplacepy/ and tests/ in parallel' },
{ title: 'Verify', detail: 'adversarially refute each candidate finding against the actual source' },
],
}
const DIMENSIONS = [
{ key: 'style', agent: 'style-maintainer' },
{ key: 'dry', agent: 'dry-maintainer' },
{ key: 'security', agent: 'security-maintainer' },
{ key: 'audit', agent: 'audit-maintainer' },
{ key: 'devii', agent: 'devii-maintainer' },
{ key: 'seo', agent: 'seo-maintainer' },
{ key: 'frontend', agent: 'frontend-maintainer' },
{ key: 'fanout', agent: 'fanout-maintainer' },
{ key: 'docs', agent: 'docs-maintainer' },
{ key: 'test', agent: 'test-maintainer' },
]
const FINDINGS_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'findings'],
properties: {
summary: { type: 'string' },
findings: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['severity', 'file', 'rule', 'message'],
properties: {
severity: { type: 'string', enum: ['error', 'warning', 'info'] },
file: { type: 'string' },
line: { type: 'integer' },
rule: { type: 'string' },
message: { type: 'string' },
},
},
},
},
}
const VERDICT_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['isReal', 'reason'],
properties: {
isReal: { type: 'boolean' },
reason: { type: 'string' },
severity: { type: 'string', enum: ['error', 'warning', 'info'] },
},
}
function requestedKeys() {
if (Array.isArray(args && args.only)) return args.only
if (typeof (args && args.only) === 'string') return args.only.split(',').map((s) => s.trim()).filter(Boolean)
return null
}
function scopedFiles() {
if (Array.isArray(args && args.files)) return args.files
return null
}
const wanted = requestedKeys()
const files = scopedFiles()
const selected = wanted ? DIMENSIONS.filter((d) => wanted.includes(d.key)) : DIMENSIONS
const scopeNote = files && files.length
? `\n\nRestrict every finding strictly to these files (you may read other files only for cross-reference):\n${files.join('\n')}`
: ''
function reportPrompt(dimension) {
return (
`Operate in REPORT mode (read-only). Do not modify any file. Scan your single quality dimension across the ` +
`devplacepy/ package and tests/, following your mandate, scope units, and accuracy doctrine. Exclude the agents/ ` +
`directory entirely. Confirm each candidate against the actual source before recording it. Return your findings as ` +
`structured output: a one-line summary and one entry per confirmed finding (severity, file, line, rule, message).` +
scopeNote
)
}
function verifyPrompt(dimension, finding) {
return (
`Adversarially verify a candidate "${dimension}" finding. Your goal is to REFUTE it. Open the exact file and read ` +
`enough surrounding context (the whole function, the caller, the contract) to judge intent. It is REAL only if it ` +
`survives refutation as a genuine violation of the ${dimension} dimension. Rule it out (isReal=false) if it is a ` +
`contract identifier, DATA rather than authored prose, generated or vendored or third-party, or already correct ` +
`under a known exemption. When uncertain, default to isReal=false.\n\n` +
`Candidate finding:\n` +
`- file: ${finding.file}\n` +
`- line: ${finding.line == null ? 'unspecified' : finding.line}\n` +
`- severity: ${finding.severity}\n` +
`- rule: ${finding.rule}\n` +
`- message: ${finding.message}\n\n` +
`Return isReal and a one-line reason.`
)
}
log(`Fleet check over ${selected.length} dimension(s)${files ? ` scoped to ${files.length} file(s)` : ''}`)
const reviewed = await pipeline(
selected,
(dimension) =>
agent(reportPrompt(dimension), {
agentType: dimension.agent,
label: `review:${dimension.key}`,
phase: 'Review',
schema: FINDINGS_SCHEMA,
}),
(review, dimension) =>
parallel(
((review && review.findings) || []).map((finding) => () =>
agent(verifyPrompt(dimension.key, finding), {
agentType: dimension.agent,
label: `verify:${dimension.key}`,
phase: 'Verify',
schema: VERDICT_SCHEMA,
}).then((verdict) => ({ ...finding, dimension: dimension.key, verdict }))
)
)
)
const candidates = reviewed.flat().filter(Boolean)
const confirmed = candidates.filter((finding) => finding.verdict && finding.verdict.isReal)
const dropped = candidates.length - confirmed.length
log(`Confirmed ${confirmed.length} finding(s); dropped ${dropped} as refuted false positive(s)`)
return {
mode: 'check',
dimensions: selected.map((dimension) => dimension.key),
candidates: candidates.length,
confirmed,
droppedAsFalsePositive: dropped,
}
+167
View File
@@ -0,0 +1,167 @@
// retoor <retoor@molodetz.nl>
export const meta = {
name: 'job-service',
description: 'Scaffold an async JobService (the zip/fork pattern): the JobService subclass, enqueue/status/download routes, the JobOut schema, main.py registration, Devii tools, JobPoller frontend, and docs, then verify',
phases: [
{ title: 'Understand', detail: 'read ZipService and ForkService as the template' },
{ title: 'Plan', detail: 'a per-touchpoint plan for the new job kind' },
{ title: 'Implement', detail: 'build the service and all consumers in the repo' },
{ title: 'Verify', detail: 'completeness, security, and audit-log review' },
{ title: 'Fix', detail: 'close gaps and write the job tests' },
],
}
const RULES = [
'Obey DevPlace hard rules while editing:',
'- No comments or docstrings in source except the file header and @tool docstrings. New files start with the "retoor <retoor@molodetz.nl>" header.',
'- No em-dash characters; use a hyphen. Full Python type hints; pathlib over os; Pydantic input with max lengths.',
'- Runtime artifacts live in config.DATA_DIR (the var/ dir), OUTSIDE the devplacepy package and NOT under /static. Heavy compression or blocking work runs in a subprocess. SQLite stays synchronous.',
'- Enqueue endpoints own authz (require_user plus any resource guard); status and download are capability URLs scoped only by the unguessable uuid7. Soft-delete the job tracking rows; permanent artifacts are not deleted by cleanup().',
'- Record audit events with record_system in the service. Frontend status polling uses JobPoller, never a bespoke loop.',
'- Validate with "python -m agents.validator ." and "python -c \\"from devplacepy.main import app\\"". NEVER run the test suite. Never perform any git write.',
].join('\n')
const CHECKLIST = [
'A new async job kind must wire all of these (mirror ZipService/ForkService):',
'1. services/jobs/{kind}_service.py - subclass JobService, set kind, implement async process(self, job) -> dict and cleanup(self, job).',
'2. main.py - register the service via service_manager.register(...).',
'3. routers/{area}.py - an enqueue route (guarded) calling queue.enqueue(kind=...), a GET status route returning a *JobOut, and a download/result route (FileResponse capability URL) where applicable.',
'4. schemas.py - the *JobOut model with every key the status JSON returns.',
'5. services/devii/actions/catalog.py - Devii tools for enqueue and status.',
'6. docs_api.py - endpoint() entries for the enqueue, status, and download routes.',
'7. static/js - wire JobPoller.run(statusUrl, {onDone, onFailed, onTimeout}) on the triggering element.',
'8. CLI (optional) - a prune/clear subcommand if artifacts accumulate.',
'9. README.md + AGENTS.md - document the new job kind.',
].join('\n')
function jobBrief() {
if (!args) return ''
if (typeof args === 'string') return args
if (typeof args.description === 'string') return args.description
return JSON.stringify(args)
}
const ask = jobBrief()
if (!ask) {
log('No job description provided. Invoke as /job-service <what heavy work to run off the request path>.')
return { error: 'no description provided' }
}
const MAP_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary'],
properties: {
summary: { type: 'string' },
template: { type: 'string' },
files: { type: 'array', items: { type: 'string' } },
},
}
const PLAN_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['steps'],
properties: {
steps: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['file', 'change'],
properties: { file: { type: 'string' }, change: { type: 'string' } },
},
},
},
}
const BUILD_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'filesChanged', 'validatorPassed'],
properties: {
summary: { type: 'string' },
kind: { type: 'string' },
filesChanged: { type: 'array', items: { type: 'string' } },
validatorPassed: { type: 'boolean' },
importOk: { type: 'boolean' },
},
}
const FINDINGS_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'findings'],
properties: {
summary: { type: 'string' },
findings: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['severity', 'file', 'rule', 'message'],
properties: {
severity: { type: 'string', enum: ['error', 'warning', 'info'] },
file: { type: 'string' },
line: { type: 'integer' },
rule: { type: 'string' },
message: { type: 'string' },
},
},
},
},
}
log(`Job service: ${ask}`)
const map = await agent(
`Read the DevPlace async job framework and the two existing consumers ZipService and ForkService end to end (services/jobs/, the enqueue/status/download routes, their *JobOut schemas, Devii tools, and frontend pollers) as the template for a new job kind. Do not write anything.\n\nJob request: ${ask}\n\n${CHECKLIST}`,
{ agentType: 'Explore', label: 'understand', phase: 'Understand', schema: MAP_SCHEMA }
)
const plan = await agent(
`Produce a per-file plan to add this new job kind, mirroring ZipService/ForkService across the checklist. One step per file. Do not write code.\n\nJob request: ${ask}\n\nTemplate map:\n${JSON.stringify(map, null, 2)}\n\n${CHECKLIST}`,
{ agentType: 'Plan', label: 'plan', phase: 'Plan', schema: PLAN_SCHEMA }
)
const build = await agent(
`Implement this new async job kind coherently, editing files directly in the repo, mirroring ZipService/ForkService and following the plan. Keep the *JobOut schema, routes, Devii tools, and docs in agreement. Then run "python -m agents.validator ." and "python -c \\"from devplacepy.main import app\\"". Do not write tests here. Do not run the suite. Do not commit.\n\nJob request: ${ask}\n\nPlan:\n${JSON.stringify(plan, null, 2)}\n\n${CHECKLIST}\n\n${RULES}\n\nReturn the job kind, files changed, and whether validator and import passed.`,
{ label: 'implement', phase: 'Implement', schema: BUILD_SCHEMA }
)
const changed = (build && build.filesChanged) || []
const scopeNote = changed.length ? `\n\nRestrict findings to these files:\n${changed.join('\n')}` : ''
const audits = await parallel(
[
{ key: 'fanout', agent: 'fanout-maintainer' },
{ key: 'security', agent: 'security-maintainer' },
{ key: 'audit', agent: 'audit-maintainer' },
{ key: 'docs', agent: 'docs-maintainer' },
].map((a) => () =>
agent(
`Operate in REPORT mode (read-only). Audit the new async job kind for your single dimension.${scopeNote}\n\nJob request: ${ask}`,
{ agentType: a.agent, label: `verify:${a.key}`, phase: 'Verify', schema: FINDINGS_SCHEMA }
).then((r) => ({ key: a.key, findings: (r && r.findings) || [] }))
)
)
const gaps = audits
.filter(Boolean)
.flatMap((r) => r.findings.map((f) => ({ dimension: r.key, ...f })))
.filter((f) => f.severity !== 'info')
let gapFix = 'no actionable gaps'
if (gaps.length) {
gapFix = await agent(
`Close these job-service gaps with minimal root-cause fixes in the repo, then re-run "python -m agents.validator .". Do not run the suite. Do not commit.\n\nGaps:\n${JSON.stringify(gaps, null, 2)}\n\n${RULES}`,
{ label: 'fix-gaps', phase: 'Fix' }
)
}
const tests = await agent(
`Operate in FIX mode. Write the integration tests for the new job kind (enqueue, status, download) following the required patterns and the directory-mirrors-path layout. Validate by a clean import only. NEVER run the suite.\n\nJob request: ${ask}\nKind: ${build && build.kind}\nFiles changed:\n${changed.join('\n')}`,
{ agentType: 'test-maintainer', label: 'tests', phase: 'Fix' }
)
return { ask, map, plan, build, audit: gaps, gapFix, tests }
+124
View File
@@ -0,0 +1,124 @@
// retoor <retoor@molodetz.nl>
export const meta = {
name: 'review',
description: 'Read-only pre-commit review of the current git diff across every DevPlace quality dimension, with adversarial verification of each finding before it is reported',
phases: [
{ title: 'Diff', detail: 'collect the changed files and a summary of the diff' },
{ title: 'Review', detail: 'each dimension reviews the diff in parallel' },
{ title: 'Verify', detail: 'adversarially refute each candidate finding against source' },
],
}
const DIMENSIONS = [
{ key: 'security', agent: 'security-maintainer' },
{ key: 'audit', agent: 'audit-maintainer' },
{ key: 'fanout', agent: 'fanout-maintainer' },
{ key: 'style', agent: 'style-maintainer' },
{ key: 'dry', agent: 'dry-maintainer' },
{ key: 'frontend', agent: 'frontend-maintainer' },
{ key: 'docs', agent: 'docs-maintainer' },
{ key: 'seo', agent: 'seo-maintainer' },
{ key: 'test', agent: 'test-maintainer' },
]
const DIFF_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['files'],
properties: {
base: { type: 'string' },
files: { type: 'array', items: { type: 'string' } },
summary: { type: 'string' },
},
}
const FINDINGS_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['summary', 'findings'],
properties: {
summary: { type: 'string' },
findings: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
required: ['severity', 'file', 'rule', 'message'],
properties: {
severity: { type: 'string', enum: ['error', 'warning', 'info'] },
file: { type: 'string' },
line: { type: 'integer' },
rule: { type: 'string' },
message: { type: 'string' },
},
},
},
},
}
const VERDICT_SCHEMA = {
type: 'object',
additionalProperties: false,
required: ['isReal', 'reason'],
properties: {
isReal: { type: 'boolean' },
reason: { type: 'string' },
},
}
function baseRef() {
if (typeof args === 'string' && args.trim()) return args.trim()
if (args && typeof args.base === 'string') return args.base
return ''
}
const base = baseRef()
const diffCmd = base
? `git diff ${base}... and git diff (unstaged) and git status --porcelain`
: `git status --porcelain, git diff, and git diff --staged`
const diff = await agent(
`Read-only. Collect the set of changed files in this repository for review using ${diffCmd}. Keep only existing files under devplacepy/ and tests/. Return the file list and a one-paragraph summary of what changed. Do not modify anything.`,
{ agentType: 'Explore', label: 'diff', phase: 'Diff', schema: DIFF_SCHEMA }
)
const files = (diff && diff.files) || []
if (!files.length) {
log('No changed files under devplacepy/ or tests/; nothing to review.')
return { files: [], confirmed: [] }
}
const fileList = files.join('\n')
log(`Reviewing ${files.length} changed file(s) across ${DIMENSIONS.length} dimensions`)
const reviewed = await pipeline(
DIMENSIONS,
(dimension) =>
agent(
`Operate in REPORT mode (read-only). Review ONLY the changes in these files for your single dimension. Read the actual diff (git diff -- <file>) and enough surrounding context to judge intent. Confirm each finding against the source.\n\nChanged files:\n${fileList}`,
{ agentType: dimension.agent, label: `review:${dimension.key}`, phase: 'Review', schema: FINDINGS_SCHEMA }
),
(review, dimension) =>
parallel(
((review && review.findings) || []).map((finding) => () =>
agent(
`Adversarially verify a candidate "${dimension.key}" review finding. Try to REFUTE it: open the file, read the changed region and its context, and decide if it is a genuine violation introduced by this diff. Rule it out (isReal=false) if it is a contract identifier, DATA rather than prose, vendored, pre-existing and untouched by this diff, or already correct under a known exemption. When uncertain, default to isReal=false.\n\nFinding:\n- file: ${finding.file}\n- line: ${finding.line == null ? 'unspecified' : finding.line}\n- severity: ${finding.severity}\n- rule: ${finding.rule}\n- message: ${finding.message}`,
{ agentType: dimension.agent, label: `verify:${dimension.key}`, phase: 'Verify', schema: VERDICT_SCHEMA }
).then((verdict) => ({ ...finding, dimension: dimension.key, verdict }))
)
)
)
const candidates = reviewed.flat().filter(Boolean)
const confirmed = candidates.filter((f) => f.verdict && f.verdict.isReal)
const dropped = candidates.length - confirmed.length
log(`Review complete: ${confirmed.length} confirmed, ${dropped} refuted`)
return {
base: base || 'working tree',
files,
candidates: candidates.length,
confirmed,
droppedAsFalsePositive: dropped,
}