Skip to main content

goal-drift

Read-only goal-drift auditor. Holds each project's immutable goal as a typed record derived only from real human prompts, inspects what the project actually produced (tickets first, then artifacts, commits, and absences), and labels every action SERVES_GOAL, SUPPORTS_INDIRECTLY, DECLARED_DRIFT, UNTICKETED_WORK, SCOPE_DRIFT or MISSING_EXPECTED with a reason. Runs nightly on cron and reports; it never edits, commits, fixes, or reprioritises. Use when asked whether work is on track, whether an agent drifted, to register or read a project's immutable goal, or to run the goal-drift check.

Ir para a instalação

Informações da origem

Repositório
grahama1970/agent-skills
Última atividade na origem
8 de agosto de 2026 às 16:32
Idioma detectado do SKILL.md
inglês
Estrelas
5
Forks
2

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
13 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
goal-drift
description
Read-only goal-drift auditor. Holds each project's immutable goal as a typed record derived only from real human prompts, inspects what the project actually produced (tickets first, then artifacts, commits, and absences), and labels every action SERVES_GOAL, SUPPORTS_INDIRECTLY, DECLARED_DRIFT, UNTICKETED_WORK, SCOPE_DRIFT or MISSING_EXPECTED with a reason. Runs nightly on cron and reports; it never edits, commits, fixes, or reprioritises. Use when asked whether work is on track, whether an agent drifted, to register or read a project's immutable goal, or to run the goal-drift check.
allowed-tools
["Bash","Read"]
triggers
["goal drift","did we drift","am I on track","scope drift","check goal drift","drift verdict","is this work serving the goal","register immutable goal","what is the immutable goal","why did we drift"]
metadata
{"short-description":"Read-only goal-vs-actions drift audit on a nightly cron","author":"Graham","version":"0.1.0","inspired-by":"nicobailon/pi-subagents watchdog scope-drift (README verified 2026-08-02)"}
runtime_self_improvement
basic
provides
["goal-registry","goal-drift-detection","scope-drift-report"]
composes
["ticket","tau","memory","goal-helper","scheduler","task-monitor","agentic-evals"]
complies
["best-practices-skills","best-practices-python","best-practices-arangodb"]
taxonomy
["operations","validation","precision","resilience","human-in-the-loop"]
disciplines
["evaluation-quality","observability-operations"]
# goal-drift **Read-only.** Observes and reports. It cannot edit files, commit, or reprioritise. A drift detector that can also act becomes one more lane to drift into. ## Related skills, easily confused | Skill | Axis | |---|---| | `/goal-helper` | **authors** a goal: proof command, completion criteria, retry limits | | `/project-drift` | **knowledge** drift: does transcript evidence stale-date `PROJECT_KNOWLEDGE.md`? | | **`goal-drift`** | **goal** drift: does the work still serve the registered immutable goal? | `/project-drift` asks *"is the documentation still true?"* This asks *"are we still doing the right thing?"* Both are real; they fail independently. Documentation can be perfectly accurate while the work wanders. ## Why it exists An immutable goal written into a document does not prevent drift. Observed 2026-08-02: a goal was recorded verbatim in a skill header, and the work still went to a compiler fix in another repo, four unrelated documentation edits, and single-employer archaeology reported as chat prose. Every step was defensible alone. None was the artifact the goal named. The `PROJECT_KNOWLEDGE` claims stayed accurate throughout, so a knowledge-drift auditor would have reported clean. Nobody noticed until the human asked. The mechanism is ported from `nicobailon/pi-subagents`, whose watchdog keeps a current-scope artifact from real user prompts and flags work that no longer serves it as `scope-drift`. That project is a Pi extension (TypeScript), so the pattern is reimplemented here rather than installed. ## The rule that makes it work **Scope comes only from real human prompts.** The agent's own intermediate goals, self-generated plans, and auto-follow steps are never admitted as scope. Without this rule an agent invents a sub-goal, pursues it, and grades itself compliant. pi-subagents makes the same exclusion: its watchdog auto-follow prompts are explicitly not recorded as scope. `register` stores `source: human_prompt` with the verbatim text. Anything marked `agent_inferred` is **refused at registration**, not warned about. ## Commands ```bash ./run.sh register --project <name> --goal-file goal.txt # human text only ./run.sh goal --project <name> # read the goal back ./run.sh check --project <name> --since 24h [--json] # the audit ./run.sh schedule # nightly cron ./sanity.sh # behavioral gates ``` Nightly: ```bash /scheduler add goal-drift --cron "0 6 * * *" --budget 5 ``` 06:00 deliberately — **after** nightly producers finish, so it grades a completed night rather than one in progress. ## Evidence hierarchy — tickets first | Rank | Evidence | Source | Why | |---|---|---|---| | 1 | **Tickets** | `/ticket` + `gh issue list` | declares intent **before** work starts | | 2 | Artifacts | criterion `artifact_globs` | did the thing actually get produced? | | 3 | Commits | `git log --since` | secondary; a commit citing **no** ticket is itself a signal | | — | **Absence** | expected artifact never produced | the case a what-happened-only checker cannot see | Tickets rank first because a ticket declares intent at filing time, so drift is catchable the day it is declared rather than weeks later in commit forensics. A lease shows what is being worked on *now*; attached proof is real acceptance evidence rather than a filename guess. Verified: a ticket titled "Fix DAG reachability in tau compiler" against a report-and-resume goal yields `DECLARED_DRIFT` with zero commits present. **Absence remains the finding that matters most.** A night with twelve commits and zero instances of the artifact the goal names *is* the drift case. ## Strict seam contracts Every boundary-crossing artifact is validated at the producer with a typed `@dataclass` + `validate()` (copy-safe, no pydantic). Exactly three outcomes: **pass, self-heal-with-record, or raise** — never warn-and-continue. Validated artifacts carry a `seam_validation` stamp so a reader can tell "validated" from "never checked". Cross-field truth checks, because field presence alone does not catch a lying summary: - `ON_GOAL` while findings contain drift markers → **refused** - `NOT_ESTABLISHED` without a `GOAL_UNREGISTERED` finding → refused - `indirect_share > indirect_cap` while claiming `ON_GOAL` → refused - `read_only: false` → refused The skill therefore cannot emit a verdict its own evidence contradicts. ## tau integration The audit is handed to `/tau` as a skill node using **`tau.generic_dag_spec.v1`** — *not* `tau.dag_contract.v1`, which tau skill nodes reject — with `tau.skill_work_order.v1` and `tau.skill_dag_node.v1`. The node declares `read_only: true` and the work order's task text carries "Never edit, commit, or reprioritise", so the constraint travels with the handoff. **Goal identity is `goal_hash`**, canonical over the goal object the way tau hashes goals: - hash covers goal **content**; `registered_at` is excluded, so re-registering identical text and criteria reproduces it - change one word of the goal and the hash changes - a revision carries the prior hash as **`goal.parent_goal_hash`** — traceable lineage, not a silent overwrite "Immutable" stops being a promise in prose and becomes something a receipt can prove. ## Verdicts | Verdict | Meaning | |---|---| | `SERVES_GOAL` | maps to an acceptance criterion | | `SUPPORTS_INDIRECTLY` | plausible enabler — **capped**, see below | | `SCOPE_DRIFT` | real work, no mapping to any criterion | | `DECLARED_DRIFT` | a **ticket** declares work matching no criterion — caught at filing time | | `UNTICKETED_WORK` | a commit cites no ticket and matches no criterion | | `MISSING_EXPECTED` | a criterion produced nothing | | `GOAL_UNREGISTERED` | no goal → report is `NOT_ESTABLISHED`, never "clean" | Run verdict: `ON_GOAL`, `DRIFTED`, `NOT_ESTABLISHED`, or **`DEGRADED`** (an evidence source failed; partial evidence can never read as on-goal). `SERVES_GOAL` from a ticket requires **closed AND attached proof**. An on-criterion ticket still open, or closed without proof, is `SUPPORTS_INDIRECTLY` and does **not** satisfy absence — "in progress" is not done. **`SUPPORTS_INDIRECTLY` is capped at 30% of actions.** Past the cap the run is `DRIFTED`, because *"it was all necessary groundwork"* is precisely the story drift tells about itself. Infrastructure that enables the goal is legitimate; infrastructure that replaces producing the goal's artifact is not. ## Report contract Leads with the verdict and the absences, never with the volume of work: ``` project: monitor-opportunities window: 24h verdict: DRIFTED MISSING_EXPECTED daily interactive report (0 produced, >=1 required) MISSING_EXPECTED tailored resume variant (0 produced) SCOPE_DRIFT tau compiler fix (no criterion references tau) SERVES_GOAL ATS tenant discovery -> criterion: discover opportunities indirect 42% exceeds cap 30% -> DRIFTED ``` An honest `DRIFTED` verdict is a **success** for this skill. It must never soften a verdict because the work looked productive. ## Non-negotiables - **No mutation.** `sanity.sh` asserts the runtime cannot write to a project tree and that no subcommand edits, commits, or reprioritises. - **No self-certification.** `agent_inferred` goals are refused. - **Absence is a finding.** Zero expected artifacts is `DRIFTED`, not silence. - **No goal means `NOT_ESTABLISHED`** — never "on track by default". - **Writes go through `/memory`**, never direct ArangoDB. ## References - `references/verdict-contract.md` — verdict definitions and the indirect cap - `fixtures/agentic_eval.json` — positive, negative, adversarial cases
Ver no GitHub