refactor(athena): strip audit bias from council member prompt + add intent addendums + write boundary hook + relax restrictions

This commit is contained in:
ismeth
2026-02-27 16:46:23 +01:00
committed by YeonGyu-Kim
parent e198707e84
commit 386645ea6b
8 changed files with 267 additions and 20 deletions
@@ -0,0 +1,167 @@
export const COUNCIL_INTENT_ADDENDUMS: Record<string, string> = {
AUDIT: `
## Analysis Intent: AUDIT
You are conducting an **audit** — your goal is to find discrete issues, risks, or violations.
**Focus:**
- Search for problems, anti-patterns, security risks, correctness issues, or violations of stated requirements
- Each finding must be a distinct, actionable item with concrete evidence
- Severity determines priority: critical (blocks/breaks), high (significant risk), medium (should fix), low (nice to fix)
- For each finding, provide the specific location (reference, section, or component where it occurs)
- State your confidence: high (clear evidence), medium (likely but needs verification), low (suspicion, investigate further)
**Required output fields per finding:**
- Title, Severity (critical/high/medium/low), Location, Confidence (high/medium/low)
- Issue description, Supporting evidence, Suggested fix
**Structure your response as:**
\`\`\`
<COUNCIL_MEMBER_RESPONSE>
## Finding 1: [Title]
- **Severity**: high
- **Location**: [specific reference — e.g. component, section, endpoint, rule]
- **Confidence**: high
- **Issue**: [what is wrong and why it matters]
- **Evidence**: [concrete reference, snippet, or observation that proves the issue]
- **Suggested Fix**: [actionable recommendation]
## Finding 2: [Title]
...
## Summary
[Total findings by severity. Overall risk assessment with confidence levels.]
</COUNCIL_MEMBER_RESPONSE>
\`\`\``,
EVALUATE: `
## Analysis Intent: EVALUATE
You are conducting an **evaluation** — your goal is to compare options against criteria and surface tradeoffs.
**Focus:**
- Identify the options available (explicit or implied by the question)
- Define evaluation criteria relevant to the context (cost, complexity, performance, maintainability, risk, etc.)
- Assess each option against each criterion with evidence, not assumptions
- Surface tradeoffs clearly — where one option wins, another likely loses
- If the question implies a recommendation is needed, provide one with conditions
**Required output fields:**
- Options identified, Criteria used, Per-option assessment, Tradeoff summary
- Conditional recommendation (if decision is required), Confidence per assessment
**Structure your response as:**
\`\`\`
<COUNCIL_MEMBER_RESPONSE>
## Options Identified
1. [Option A] — [brief description]
2. [Option B] — [brief description]
## Criteria & Assessment
| Criterion | Option A | Option B |
|-----------|----------|----------|
| [e.g. Complexity] | [assessment] | [assessment] |
## Tradeoff Summary
- Option A excels at [X] but sacrifices [Y]
- Option B excels at [Y] but sacrifices [X]
## Recommendation
[If applicable: "Choose A if [condition]; choose B if [condition]"]
- **Confidence**: [level and reasoning]
## Risks & Unknowns
[Uncertainties that could change the recommendation]
</COUNCIL_MEMBER_RESPONSE>
\`\`\``,
PLAN: `
## Analysis Intent: PLAN
You are conducting a **planning analysis** — your goal is to define current state, target state, and a phased path between them.
**Focus:**
- Assess where things stand now (current state, constraints, existing assets)
- Define the target state clearly (what "done" looks like)
- Break the path into phases with sequencing, dependencies, and exit criteria
- Identify risks per phase and mitigation strategies
- Estimate effort where possible (relative sizing is fine: small/medium/large)
**Required output fields:**
- Current state assessment, Target state definition
- Phases (each with: goal, tasks, exit criteria, dependencies, risks, effort estimate)
- Critical path, Key risks and mitigations
**Structure your response as:**
\`\`\`
<COUNCIL_MEMBER_RESPONSE>
## Current State
[What exists today, constraints, and starting conditions]
## Target State
[What "done" looks like — measurable where possible]
## Phase 1: [Name]
- **Goal**: [what this phase achieves]
- **Tasks**: [concrete work items]
- **Exit Criteria**: [how you know this phase is complete]
- **Dependencies**: [what must be true before starting]
- **Risks**: [what could go wrong, with mitigation]
- **Effort**: [small/medium/large or time estimate]
## Phase 2: [Name]
...
## Critical Path & Dependencies
[Which phases block others, what the minimum viable sequence is]
## Summary
[Overall effort assessment, key risks, confidence in feasibility]
</COUNCIL_MEMBER_RESPONSE>
\`\`\``,
EXPLAIN: `
## Analysis Intent: EXPLAIN
You are conducting an **explanatory analysis** — your goal is to build understanding of how something works, why it exists, or what it means.
**Focus:**
- Lead with a clear thesis statement — your one-sentence answer to the question
- Identify the key mechanisms, components, or concepts that drive the answer
- Provide evidence and references for each mechanism (not just assertions)
- Map relationships, data flows, or causal chains between components
- Acknowledge unknowns, gaps in evidence, and areas of uncertainty
- Works for any domain: architecture, external systems, abstract concepts, research topics
**Required output fields:**
- Thesis statement, Key mechanisms/components (with evidence)
- Relationships and interactions, Evidence references
- Unknowns and knowledge gaps, Overall confidence
**Structure your response as:**
\`\`\`
<COUNCIL_MEMBER_RESPONSE>
## Thesis
[One clear sentence answering the core question]
## Key Mechanisms
### 1. [Mechanism/Component Name]
- **What**: [description]
- **Evidence**: [reference, observation, or reasoning]
- **Role**: [how this contributes to the overall answer]
### 2. [Mechanism/Component Name]
...
## Relationships & Interactions
[How the mechanisms connect — data flows, dependencies, causal chains]
## Unknowns & Gaps
- [What you could not determine or verify]
- [Areas where confidence is lower and why]
## Summary
[Synthesized explanation with overall confidence level]
</COUNCIL_MEMBER_RESPONSE>
\`\`\``,
}
+9 -18
View File
@@ -4,33 +4,26 @@ import { createAgentToolAllowlist } from "../../shared"
const MODE: AgentMode = "subagent"
export const COUNCIL_MEMBER_PROMPT = `You are an independent code analyst in a multi-model analysis council. Your role is to provide thorough, evidence-based analysis.
export const COUNCIL_MEMBER_PROMPT = `You are an independent analyst in a multi-model analysis council. Your role is to provide thorough, evidence-based analysis.
## Your Role
- You are one of several AI models analyzing the same question independently
- Your analysis should be thorough and evidence-based
- You are read-only — you cannot modify any files, only analyze
- Focus on finding real issues, not hypothetical ones
## Instructions
1. Analyze the question carefully
2. Search the codebase thoroughly using available tools (Read, Grep, Glob, LSP)
3. Report your findings with evidence (file paths, line numbers, code snippets)
4. For each finding, state:
- What the issue/observation is
- Where it is (file path, line number)
- Why it matters (severity: critical/high/medium/low)
- Your confidence level (high/medium/low)
5. Be concise but thorough — quality over quantity
2. Use available tools to gather evidence relevant to the question
3. For each point, state what you observed, where (if applicable), and your confidence level
4. Be concise but thorough — quality over quantity
## Response Format (MANDATORY)
You MUST wrap your final analysis in <COUNCIL_MEMBER_RESPONSE> tags. This is how the system extracts your findings.
**Include inside tags:**
- Key findings with evidence (file paths, line numbers, code snippets)
- Key findings with supporting evidence
- Confidence levels for each finding (high/medium/low)
- Severity assessments (critical/high/medium/low)
- Concerns and caveats
**Exclude from tags (keep outside):**
@@ -41,14 +34,12 @@ You MUST wrap your final analysis in <COUNCIL_MEMBER_RESPONSE> tags. This is how
**Example structure:**
\`\`\`
<COUNCIL_MEMBER_RESPONSE>
## Finding 1: [Title]
- **Location**: src/path/to/file.ts:42-56
- **Severity**: high
## Point 1: [Title]
- **Observation**: [what you found]
- **Confidence**: high
- **Issue**: [description]
- **Evidence**: [code snippet or reference]
- **Details**: [supporting evidence or reasoning]
## Finding 2: [Title]
## Point 2: [Title]
...
## Summary
@@ -0,0 +1,5 @@
import { ATHENA_AGENT } from "./constants"
export function isAthenaAgent(agentName: string | undefined): boolean {
return agentName?.toLowerCase().includes(ATHENA_AGENT) ?? false
}
@@ -0,0 +1,5 @@
export const HOOK_NAME = "athena-sisyphus-only"
export const ATHENA_AGENT = "athena"
export const BLOCKED_TOOLS = ["Write", "Edit", "write", "edit"]
+49
View File
@@ -0,0 +1,49 @@
import type { PluginInput } from "@opencode-ai/plugin"
import { HOOK_NAME, BLOCKED_TOOLS } from "./constants"
import { log } from "../../shared/logger"
import { getAgentFromSession } from "../prometheus-md-only/agent-resolution"
import { isAthenaAgent } from "./agent-matcher"
import { isAllowedPath } from "./path-policy"
export function createAthenaSisyphusOnlyHook(ctx: PluginInput) {
return {
"tool.execute.before": async (
input: { tool: string; sessionID: string; callID: string },
output: { args: Record<string, unknown>; message?: string }
): Promise<void> => {
if (!BLOCKED_TOOLS.includes(input.tool)) {
return
}
const agentName = await getAgentFromSession(input.sessionID, ctx.directory, ctx.client)
if (!isAthenaAgent(agentName)) {
return
}
const filePath = (output.args.filePath ?? output.args.path ?? output.args.file) as string | undefined
if (!filePath) {
return
}
if (!isAllowedPath(filePath, ctx.directory)) {
log(`[${HOOK_NAME}] Blocked: Athena attempted write outside .sisyphus/`, {
sessionID: input.sessionID,
tool: input.tool,
filePath,
agent: agentName,
})
throw new Error(
`[${HOOK_NAME}] Athena can only write/edit files inside .sisyphus/ directory. Attempted to modify: ${filePath}`
)
}
log(`[${HOOK_NAME}] Allowed: .sisyphus/ write permitted`, {
sessionID: input.sessionID,
tool: input.tool,
filePath,
agent: agentName,
})
},
}
}
+2
View File
@@ -0,0 +1,2 @@
export * from "./constants"
export { createAthenaSisyphusOnlyHook } from "./hook"
@@ -0,0 +1,30 @@
import { relative, resolve, isAbsolute } from "node:path"
/**
* Cross-platform path validator for Athena file writes.
* Uses path.resolve/relative instead of string matching to handle:
* - Windows backslashes (e.g., .sisyphus\\notepads\\x.yaml)
* - Mixed separators (e.g., .sisyphus\\plans/x.md)
* - Case-insensitive directory matching
* - Workspace confinement (blocks paths outside root or via traversal)
* - No extension restriction: any file type is allowed inside .sisyphus/
*/
export function isAllowedPath(filePath: string, workspaceRoot: string): boolean {
// 1. Resolve to absolute path
const resolved = resolve(workspaceRoot, filePath)
// 2. Get relative path from workspace root
const rel = relative(workspaceRoot, resolved)
// 3. Reject if escapes root (starts with ".." or is absolute)
if (rel.startsWith("..") || isAbsolute(rel)) {
return false
}
// 4. Check if .sisyphus/ or .sisyphus\ exists anywhere in the path (case-insensitive)
if (!/\.sisyphus[/\\]/i.test(rel)) {
return false
}
return true
}
-2
View File
@@ -48,8 +48,6 @@ const AGENT_RESTRICTIONS: Record<string, Record<string, boolean>> = {
},
athena: {
write: false,
edit: false,
call_omo_agent: false,
},