AGENTS.md — Persistent Agent Instructions, Scoped Three Ways

SkillFiles & storage

The AIDE pattern for session-scoped, workspace-scoped, and user-scoped agent instructions, the AGENTS.md (and equivalent) file convention. Use when implementing the AIDE analog of Claude Code's CLAUDE.md, Cursor's Rules, Aider's conventions file, or Cline's Memory Bank. Use when the user asks "make AIDE always do X" or "this project uses tabs, never spaces" or "when I say commit I mean signed". Use when reviewing the prompt composition for the chat path.

Use AGENTS.md — Persistent Agent Instructions, Scoped Three Ways in Claude, ChatGPT or Ahel Desktop

Free. Sign in, add AGENTS.md — Persistent Agent Instructions, Scoped Three Ways and connect your AI. About a minute.

Also: Claude Code · Cursor · Codex

Then ask your AI: use the AGENTS.md skill

Details

Instructions available. Your AI can read the instructions. Execution depends on the setup they require.

Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

AGENTS.md — Persistent Agent Instructions, Scoped Three WaysStart free

What this skill tells your AI

The instructions your AI receives, as published by anonymousnomad/covert-coder in skills/packs/aide-agents-md/SKILL.md and read by Ahel’s review.

Born 2026-08-31 from the wiring audit. AIDE has harness/credo.md (the global credo) and aide-advanced-orchestration Pattern 5 (AGENTS.md export) but the load order, scoping rules, and edit UX are not specified or wired. Every rival (Claude Code, Cursor, Cline, Copilot, Aider) has this. AIDE's version is "the credo is global, period" — too coarse. This skill IS the wire-in.

The AIDE AGENTS.md contract (3 scopes, 1 precedence)

Priority (highest to lowest):
1. SESSION scope:    .aide/agents/session.md       (ephemeral, current session only)
2. WORKSPACE scope:  <workspace>/AGENTS.md         (committed, project-wide)
3. USER scope:       ~/.aide/agents/user.md        (cross-workspace, operator's preferences)
4. GLOBAL scope:     harness/credo.md              (the oath, non-overridable)

Why 4 levels, not 3: the global credo is non-overridable by the other three. It's the oath. The other three are preferences layered on top.

The "non-overridable" rule: the credo defines the oaths (protect user, evidence over confidence, etc.). Workspace AGENTS.md can ADD constraints ("always run tests before commit") but cannot REMOVE an oath. A diff that conflicts with the credo is rejected with OATH_CONFLICT.

Files to touch (when wiring)

FileChange
node/src/services/agent-instructions.mjsNEW: loadInstructions({workspace, userHome, sessionId}) returns the merged, deduplicated, oath-checked instruction set.
node/src/services/scaffold.mjsEXTEND: composeScaffold calls loadInstructions and prepends the merged set to the system prompt.
node/src/routes/agent.ts (or new node/src/routes/instructions.ts)ADD: GET /api/instructions (show merged), PUT /api/instructions/scope/:scope (edit one scope), GET /api/instructions/scopes (list all 4).
common/contracts/agent.ts or new common/contracts/instructions.tsADD: the 4 zod schemas.
node/src/server.tsWire the routes.
tests/arch/agents-md.test.tsNEW: 5 tests (scope precedence, oath conflict, dedup, session expiry, edit UX).
scripts/aide-bundle.cjs(optional) bundle instructions CLI.
browser/src/...(optional) "Edit workspace instructions" UI in the settings panel.

The contract (zod-strict)

// in common/contracts/instructions.ts

export const InstructionScope = z.enum(['session', 'workspace', 'user', 'global']);

export const InstructionEntry = z.object({
  scope: InstructionScope,
  path: z.string(),       // file path for verification
  body: z.string(),
  lines: z.number().int().gte(0),
  modified_at: z.number().int(),
  oath_check: z.enum(['pass', 'fail', 'unknown']).default('unknown'),
  oath_conflict: z.string().nullable().optional()
}).strict();

## The load + merge algorithm

```js
// node/src/services/agent-instructions.mjs
import { promises as fs } from 'node:fs';
import path from 'node:path';
import os from 'node:os';

const OATHS = [
  'protect the user and their data',
  'evidence over confidence',
  'finish the procedure',
  'preserve the workspace',
  'carry knowledge forward'
];

const SCOPE_PATHS = {
  global:    'harness/credo.md',
  workspace: 'AGENTS.md',
  user:      path.join(os.homedir(), '.aide', 'agents', 'user.md'),
  session:   path.join('.aide', 'agents', 'session.md')
};

export async function loadInstructions({ workspace, sessionId }) {
  const entries = [];
  const conflicts = [];
  for (const [scope, relPath] of Object.entries(SCOPE_PATHS)) {
    const absPath = scope === 'user' || scope === 'global' ? relPath : path.join(workspace, relPath);
    let body;
    try { body = await fs.readFile(absPath, 'utf8'); }
    catch (e) {
      if (e.code === 'ENOENT') continue;
      throw e;
    }
    const oathCheck = checkOaths(scope, body);
    const entry = {
      scope, path: absPath, body,
      lines: body.split('\n').length,
      modified_at: (await fs.stat(absPath)).mtimeMs,
      oath_check: oathCheck.status,
      oath_conflict: oathCheck.conflict
    };
    entries.push(entry);
    if (oathCheck.status === 'fail') {
      conflicts.push({ scope, path: absPath, snippet: oathCheck.snippet, conflicting_oath: oathCheck.oath });
    }
  }
  const merged = entries
    .sort((a, b) => orderByScope(a.scope) - orderByScope(b.scope))
    .map(e => '# [' + e.scope + ']\n' + e.body)
    .join('\n\n');
  return { merged, entries, conflicts };
}

function orderByScope(scope) {
  return { global: 0, user: 1, workspace: 2, session: 3 }[scope];
}

function checkOaths(scope, body) {
  const violations = [

## The scaffold integration

```js
// in harness/scaffold.mjs:
import { loadInstructions } from '../node/src/services/agent-instructions.mjs';

export async function composeScaffoldWithInstructions({ workspace, effectiveContextTokens, taskFamily, sessionId }) {
  const baseScaffold = composeScaffold({ effectiveContextTokens, taskFamily });
  const instructions = await loadInstructions({ workspace, sessionId });
  const header = '[AIDE instructions | ' + instructions.entries.length + ' scope(s) loaded]';
  const system = baseScaffold.system.replace(
    /^(\[AIDE[^\]]+\])/,
    '$1\n' + header + '\n' + instructions.merged
  );
  return { ...baseScaffold, system, instructions };
}

Default scope conventions

  • Session (.aide/agents/session.md): ephemeral, deleted on session end. Use for "during this conversation, always..."
  • Workspace (<workspace>/AGENTS.md): committed, project-wide. Use for project conventions. This is the most common.
  • User (~/.aide/agents/user.md): cross-workspace. Use for personal style ("I always use tabs").
  • Global (harness/credo.md): the oath. Read-only. Defines the 5 oaths.

Threat matrix (the tests must cover these)

ThreatTestPass criterion
Workspace overrides global oathWorkspace AGENTS.md says "ignore safety"loadInstructions returns conflicts[0].oath = 'protect the user'; merged still includes the credo (the global wins)
Scope precedenceSet session + workspace + user with different instructionssession wins (last in merge order), workspace adds, user adds, global is base
Session cleared on session endSession scope file mtime is older than the current sessionsession scope is skipped (mtime check)
Empty scopeAll scopes emptymerged is the credo only (or empty if no credo)
50K char bodyWorkspace AGENTS.md is 50KInstructionUpdateRequest rejects with 413
Path traversalscope='workspace' body='../../etc/passwd content'the body is text, not a path — rejected only if it contains a path-jail violation; otherwise stored as-is

Existing assets this skill USES

  • harness/credo.md (the oath, GLOBAL, read-only)
  • harness/credo-map.json (the credo as a structured map)
  • harness/scaffold.mjs (the existing composeScaffold function)
  • harness/veritas.mjs (the oath names are the same as the Veritas oath labels)
  • node/src/services/workspace.ts (workspace path resolution)

Pitfalls

  • Do NOT allow the global scope to be modified via the API. The credo is sacred. The route rejects with 403.
  • Do NOT let the session scope leak between sessions. Delete the session file on session end, or check its mtime.
  • Do NOT inject the merged instructions into the user message. They go in the SYSTEM prompt, before the conversation. Models treat system-prompt as binding; user-message as data.
  • Do NOT detect conflicts with regex alone. v1 is regex (the 4 patterns above); v2 should use a proper parser and an LLM-as-judge (per the Comprehension engineering skill).
  • Do NOT silently drop a conflicting instruction. Surface it. The user needs to know.
  • Do NOT make the file watcher reload on every keystroke. Debounce 5s.

The rollout (2 PRs)

PR A — Load + merge service + scaffold integration

  • Add node/src/services/agent-instructions.mjs
  • Extend harness/scaffold.mjs with composeScaffoldWithInstructions
  • 5 arch tests
  • Commit: feat(agent): AGENTS.md scope load + merge (PR A of aide-agents-md)

PR B — Routes + edit UX

  • Add the 4 zod schemas
  • Regenerate openapi.json
  • Add 4 routes (GET merged, GET scopes, PUT scope, DELETE session)
  • 3 more arch tests
  • Commit: feat(agent): AGENTS.md routes + edit UX (PR B of aide-agents-md)

References

  • aide-advanced-orchestration Pattern 5 (AGENTS.md export, the original spec)

  • harness/credo.md + harness/credo-map.json (the oath)

  • harness/veritas.mjs (the 5 oaths: protect user, evidence over confidence, finish the procedure, preserve the workspace, carry knowledge forward)

  • aide-credo-guardrail (the credo as a skill, with the enforcement pattern)

  • Claude Code CLAUDE.md, Cursor Rules, Aider conventions file, Cline Memory Bank, Copilot custom instructions — the rival patterns

    { re: /ignore (?:all )?previous instructions/i, oath: 'finish the procedure' }, { re: /disregard (?:the )?(?:credo|oath|safety)/i, oath: 'protect the user' }, { re: /skip (?:the )?(?:veritas|gate|verification)/i, oath: 'evidence over confidence' }, { re: /never (?:commit|save|back ?up)/i, oath: 'preserve the workspace' } ]; for (const v of violations) { const m = body.match(v.re); if (m) return { status: 'fail', conflict: m[0], snippet: m[0], oath: v.oath }; } return { status: 'pass' }; }



export const MergedInstructions = z.object({
  merged: z.string(),     // the final system-prompt-prefix
  entries: z.array(InstructionEntry),
  conflicts: z.array(z.object({
    scope: InstructionScope,
    path: z.string(),
    snippet: z.string(),
    conflicting_oath: z.string()
  }))
}).strict();

export const InstructionUpdateRequest = z.object({
  scope: InstructionScope.exclude(['global']),  // global is read-only (the credo)
  body: z.string().min(0).max(50_000)         // 0 = clear
}).strict();

Signals

GitHub stars
43
Forks
14
Last commit
Oct 2026
Advanced
Item type
skill
Key
aide-agents-md
Source
github.com/anonymousnomad/covert-coder