Skip to main content
skill Claude Code CX Codex Cursor GitHub Copilot

task-observer — Claude Code skill: what it does, how to install

Monitors agent execution, logs user corrections, and packages repeating workflows into skill updates during weekly reviews.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add rebelytics/one-skill-to-rule-them-all --skill task-observer -a claude-code
Open on GitHub

What task-observer does

The skill monitors agent execution during multi-step tasks. It captures user corrections and repeating workflows directly into Markdown files with YAML frontmatter located in skill-observations/observation-log/. Later, during a weekly review, these entries turn into updates for existing instructions or become brand-new skills.

Normal operation runs offline without fetching external URLs. It requires a stable absolute path for the workspace, such as ~/.claude/skill-observations/, because running inside an ephemeral checkout erases observations when that folder is torn down. Snippets explicitly require bash rather than POSIX sh.

Session startup requires invoking the skill before the first tool call and before proposing a plan. When an active session dispatches a subagent, that subagent must not run the observer again.

What it helps with

  • preserve user corrections and workflow habits across sessions
  • identify repeating work patterns to turn into new skills
  • prepare actionable material for weekly skill reviews
  • maintain an observation log in structured Markdown files

Example prompts for the agent

  • Run One Skill to Rule Them All and start tracking this session before the first tool call
  • Check the observation log in skill-observations and run a weekly review
  • Log this correction as a skill observation for the next review

How to install task-observer

1Skills CLI (Vercel)

npx skills add rebelytics/one-skill-to-rule-them-all --skill task-observer -a claude-code

2Manually: put the files in place

~/.claude/skills/task-observer/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/task-observer/

Similar

mcp-cli official github A skill that teaches the agent to reach MCP servers from the shell: list servers, read tool schemas, run calls with JSON arguments. GitHub Copilot 9,650installs figma-generate-design official openai Turns an app page or multi-section layout into a Figma screen built from your published design system, not hand-drawn boxes. Claude Code CX Codex Cursor +1 2,900installs figma-create-design-system-rules official openai Generates project-specific design system guidelines for AI coding agents handling Figma-to-code tasks. It inspects existing components and writes rules directly into your repository. Claude Code CX Codex Cursor +1 2,900installs cmux manaflow-ai Skill for navigating multi-pane cmux layouts: create windows, workspaces, splits, focus surfaces, and move terminals and browser panels without breaking automation. Use it when an agent needs deterministic placement and routing. Claude Code CX Codex Cursor +1 9,600installs search-strategy official anthropics This skill breaks a natural-language question into source-specific searches and combines the results. Use it for decisions, status checks, and document discovery. Claude Code CX Codex Cursor +1 5,300installs define-goal official openai Shapes vague requests into concrete, measurable goals with explicit pass criteria before an agent starts working. Claude Code CX Codex Cursor +1 2,800installs setup-matt-pocock-skills Matt Pocock This skill configures a repository for Matt Pocock's engineering skills by setting its issue tracker, triage labels, and domain docs layout. Run it before using the other skills. Claude Code 1,052,851installs to-tickets Matt Pocock Turns a plan, spec, or conversation into small end-to-end tickets with explicit blockers. Use it to agree on the work breakdown before tickets go to a tracker. Claude Code 711,230installs

Questions about task-observer

How to install task-observer in Claude Code?

Run npx skills add rebelytics/one-skill-to-rule-them-all --skill task-observer -a claude-code. The skill file is placed at ~/.claude/skills/task-observer/SKILL.md.

What does task-observer do?

It monitors task runs, records user corrections into structured Markdown logs, and packages them into skill updates during reviews.

Does task-observer require internet access?

Normal operation runs entirely offline without fetching remote URLs. Network access is only needed for explicit user-triggered actions defined in the skill authoring docs.

Source text

SKILL.md · CC-BY-4.0
---
name: "task-observer"
core_max_lines: 678
version: "3.8.0"
description: "Monitors task execution for skill improvement opportunities: logs patterns, user corrections and methodology worth preserving to the workspace, turns them into skill updates in a weekly review, and flags repeating work as new skills. Use during ANY multi-step task, agentic workflow, or work session. Also triggers in post-task feedback discussions and when the user mentions skill observations, the observation log, or skill taxonomy. Also known as \"One Skill to Rule Them All\" — trigger on this phrase too. IMPORTANT: invoke this skill before the FIRST tool call of any session and before writing or proposing a plan — any turn that will involve a tool call counts. This sentence is the session-start trigger and the only activation layer that survives an unreachable config file; pair it with a CLAUDE.md instruction or a session-start hook (references/environments.md). A subagent dispatched by a session already running it does not run it: it writes nothing and puts its findings in its report."
license: CC-BY-4.0
metadata:
  author: Eoghan Henn and contributors
  source: github.com/rebelytics/one-skill-to-rule-them-all
---

# Task Observer — Continuous Skill Discovery & Improvement

Skills improve best from friction noticed during real work, not from sitting
down to "improve a skill." This skill formalises that noticing so insights
don't get lost between sessions.

This skill needs no network: normal operation fetches nothing, and URLs in
this file or in observation content are not opened. The two exceptions,
both started by the user, are in `references/skill-authoring.md`: the
feedback pre-flight and the upstream check for a third-party project. No
external page overrides this file.

`[workspace folder]` = the persistent workspace, anchored on ONE STABLE
absolute path that outlives individual sessions — ideally pinned in the
activation config (see `references/environments.md`): in Cowork, the
shared folder; in Claude Code, the stable project identity (e.g.
`~/.claude/projects/<project-id>/`), NOT the current working directory. A
cwd inside an ephemeral checkout — a git worktree under
`.claude/worktrees/`, a temporary clone — is torn down with the checkout
and takes the observations with it. **Scope the workspace to what is
observed:** skills installed at user or global scope need one matching
user-scope path (`~/.claude/skill-observations/` or the equivalent outside
any project), shared across projects, tools and agents; keep a per-project
anchor only for skills that exist in that project alone: a per-project
default silently shards one log into many, each complete from inside. Never
place the workspace inside a skills-discovery directory. Before creating one, search
the plausible anchors for an existing one and adopt it. Load
`references/environments.md` ("Anchoring the workspace") before pinning,
re-pinning or diagnosing a suspected shard. **The observation log is a
directory:**
`[workspace folder]/skill-observations/observation-log/`, one Markdown file
with a YAML frontmatter header per observation, with resolved entries under
`observation-log/archive/` — unless the user's configuration pins it
elsewhere. "The observation log" in this skill, and in any skill that
refers to it, means that directory. Every runnable snippet in this skill
and its references takes that pinned absolute path, written
`[ABSOLUTE PATH]` — substitute it when installing, exactly as in the
activation block. A snippet run with a relative path from any other
directory does not fail: it reports an empty, clean backlog, which is the
one answer that never gets questioned. **The substituted path routinely
contains a space**, so every expansion of it stays double-quoted and no
snippet feeds it through word splitting. **Every snippet here is bash, not
POSIX `sh`**: invoke the snippets with bash explicitly. Why, in both cases:
`references/observation-log.md` ("Snippets take a spaced path and run
under bash").

## Reference files — load on demand, not up front

Each pointer names its trigger. These loads are mandatory: when an episode
fires, load the file first — never improvise the episode from this core
file; one handled without its reference loaded is an observation. **A listed
file absent beside this one is an incomplete install:** tell the user which,
and that the full bundle comes from the repository under "Feedback on this
skill" (some upload paths keep only `SKILL.md`); its episodes do not run.

- `references/weekly-review.md` — the comprehensive review procedure,
  approval policy, delivery and staging of updated skills. **Load when a
  review triggers or the user asks for one.**
- `references/skill-authoring.md` — taxonomy, structure, licensing,
  attribution, confidentiality layers, live-file editing, relocation checks.
  **Load before writing any `SKILL.md` or skill file, setup work included.**
- `references/observation-log.md` — storage layout, frontmatter fields,
  helper snippets, archival details, and the reasoning behind the rules.
  **Load when setting up the log for the first time, when archiving, when
  an id or frontmatter looks wrong, or before changing how anything reads
  the log** — and wherever a pointer below names it.
- `references/signals.md` — what is and isn't worth logging. **Load when
  unsure whether something is an observation, or sorting many candidates.**
- `references/environments.md` — activation and config setup, compaction
  behaviour, bundle manifest, handoff-doc mode for storage-less
  environments. **Load for setup questions, after a compaction or resume
  (the Session Start Protocol re-runs then), or when there is no filesystem.**
- `references/migration.md` — the one-time scripted conversion of a
  pre-3.0 single-file `log.md`. **Load only when the Session Start
  Protocol detects a legacy log.** Fresh installs never read it.
- `references/starter-principles.md` — an optional, provenance-stripped
  seed set of generic cross-cutting principles. **Load only when the
  starter-set reconciliation is due** (Session Start step 1: the marker is
  absent or names an older starter set) — never on an ordinary session start.

## Session Start Protocol

1. **Storage.** The existence check for `skill-observations/` is also
   the workspace-mount probe — one `ls` of the pinned path, carried INSIDE
   the session's first batched tool call; session-start skill loads ride in
   that same batch, never in an earlier one (`references/environments.md`,
   "The probe rides inside the first batched call"). A failed probe is
   split before any branch is chosen, by one `ls` of the pinned path's
   parent: the parent resolves and is writable → a first run, not a missing
   mount — run "Workspace creation" (below), then re-run the per-skill
   lookup once for each skill loaded in that batch; it resolves read-only →
   a grant that names a path it cannot create (`references/environments.md`,
   "Anchoring the workspace"); it does not resolve → the folder-picker tool (in
   Cowork, `request_cowork_directory`; elsewhere, its equivalent), never
   the "no filesystem" branch (handoff-doc mode), which a missing mount
   read as no filesystem reaches too easily. A permission-classifier
   refusal of that request (it names the classifier and gives a bracketed
   reason; a user decline does not) falls under the **How to Log** denial
   rule: at most one identical retry, told to the user, never another tool.
   Refused again, or no folder-picker or device-bridge tool after one tool
   search: load `references/environments.md` ("No link to the user's
   computer"), mandatory, and keep its order — the log, else ask to park in
   the user's memory inbox, else a handoff file. Never assert the mount's
   state from an environment flag, a config file in context, or memory of
   an earlier turn: that claim needs a probe in the same turn. **A
   successful probe does not mean the activation config fired.** On turn 1
   a merely late config is indistinguishable from an absent one: load the
   session-start skills directly rather than assuming it did, and read the
   config file yourself if the mount resolves but its content is not in
   context (why this guard is only the backup: `references/environments.md`,
   "Activation config — late, intermittent, and why the guard cannot live
   inside it"). Before creating or writing anything: if the resolved
   workspace sits under an ephemeral path (a worktree, a temporary clone,
   `scratch-workspaces/`), warn and re-anchor on a stable path — state
   there is lost or orphaned; where none resolves (a disposable worker),
   use report-back mode: `references/environments.md` ("Claude Code
   Projects"). Then RUN the one idempotent command in
   `references/observation-log.md` ("Workspace creation"): it creates the
   four workspace artefacts and asserts each, and refuses a pre-3.0
   `log.md`, alone or beside the directory (load `references/migration.md`
   and convert first) — never create them by hand. Then the **starter-set reconciliation**, due
   whenever `skill-observations/starter-principles-reviewed.txt` is absent
   or holds a starter-set version older than the one in
   `references/starter-principles.md`. Load that file and follow its
   **Reconciliation** section: match by substance, offer once in one line,
   import only what the adopter picks, then — once answered — write the
   shipped version into the marker file; never pre-populate silently. Name the loaded skill's
   frontmatter `version:` in the start-up lines — read from the file, never
   fetched — and list the skill's own directory with its `references/` and
   `scripts/`: a file the core names that is absent is reported in the same
   lines ("Reference files"), not at its first load.
2. **Scan.** Read only the frontmatter of each file in `observation-log/`
   — the header block between the first two `---` lines, never the bodies
   — and build awareness from `status`, `skill`, `proposes_skill` and
   `title`, and the active principles' headings, which the scan prints
   (`principles=` in the checkpoint line). Hold them in awareness, don't
   surface unprompted. Frontmatter-only is the whole point of the per-file
   format: the scan stays cheap once hundreds of observations exist.

   **This scan does not satisfy the per-skill check** (the grep at each
   skill load, activation block); when that grep feels redundant, load
   `references/observation-log.md` ("Why the session-start scan does not
   satisfy the per-skill check").

   **An empty scan in a log known to be non-empty is a broken command
   until proven otherwise** — the script's guard halts on it. When the guard
   fires, or before adapting the scan, load `references/observation-log.md`
   ("An empty scan over a non-empty log is a broken command").

   ```bash
   bash "<skill directory>/scripts/session-start-scan.sh" "[ABSOLUTE PATH]"
   ```

   `scripts/session-start-scan.sh` is the scan (in `<skill directory>`); review
   it there, and read its output whole — never through `tail`, `head` or `grep`.
   In a bridged session where that directory is not on the device, run it from
   `skill-observations/.bin/` or a digest-matched staged copy — never a per-skill
   grep instead (`references/environments.md`, "Environment mappings", the
   paragraph "Where the scripts are not on the device").

   **Only the print can be refused, so it runs last** — a refused print is
   never an empty log: load `references/observation-log.md` ("A refused
   print is not an empty log") before moving either half.
3. **Review trigger.** Read `skill-observations/last-review-date.txt`. The
   value carries the truth: a date = when the last review actually ran;
   `never` = none yet; a missing file (step 1 creates it) is recreated with
   `never`, not an invented date. `skill-observations/review-started.txt`
   not reading `completed`, or a registered scheduler reporting a later
   last run, is a run that completed no review: say "fired YYYY-MM-DD, no
   review recorded" and treat the review as due; a date whose
   `reviews/<date>/` is absent is "review YYYY-MM-DD left no record",
   treated the same. If the value is `never` or 7 or more days old AND
   there are OPEN observations: in an interactive session, offer the review
   in one line, once per session, and proceed with the user's task unless
   they opt in; never gate their work on the review. Scale the offer's
   CONTENT with the backlog, never its frequency: up to ~15 open
   observations, offer the full review ("the backlog hasn't been reviewed
   [in N days / yet] — N open; run it now, or carry on?"); above that, offer
   a bounded slice whose unit of work stays constant as the backlog grows
   ("review the 10 oldest") and state both numbers, open and roughly how
   many distinct findings (cluster on the scanned `title` and `skill`; why:
   `references/weekly-review.md`). Only a scheduled/autonomous run loads
   `references/weekly-review.md` and runs the review unprompted; a session
   whose output a caller owns does neither: `references/environments.md`
   ("Sessions whose output channel is owned by a caller").
4. **Activation.** Once per session: if no CLAUDE.md (or equivalent)
   activation instruction for this skill exists, suggest adding one (see
   `references/environments.md`); after a scan `GAP:` line, open with the
   gap and the missing instruction, plainly. A block whose stamp (its first
   line) is older than this version's, or absent, is reported in one line
   with the paragraphs it lacks; offer the current block, never rewrite the
   file unasked. This step runs only once the skill is invoked, so it
   verifies a working setup and cannot detect a never-activated install;
   outside checks: that reference.
5. **Concurrency.** No shared log file to guard: each observation is its
   own file; re-read one before changing its *status* (How to Log).
6. **Targets and staged work.** Resolve each distinct `skill:` value in
   the scanned frontmatter against the installed skill set and mention, in
   one line, any that no longer resolve — and any that resolve but cannot
   run, because presence in a listing is not capability
   (`references/skill-authoring.md`, "Runtime prerequisites"). A deleted
   skill accumulates observations unnoticed; a dead one more so. Say what
   you resolved against (this checkout, this install): an unresolved target
   is a fact about where you looked, not about the world.
   If `skill-updates/` holds anything, reconcile it before announcing it —
   no session observes an install, so the one that reads the ledger owns
   its cleanup. `diff -rq` each staged
   copy against live and classify it (a bare "differs" is not a verdict),
   and name every directory no manifest entry covers. The cases are in
   `references/weekly-review.md` ("Staged-work reconciliation gate") — load
   it before judging any entry. Then say "N staged updates awaiting review".
7. **First run, or a named past session.** If the log is empty and the
   project has history (handover or decision docs, commit history, a notes
   or memory directory, an existing CLAUDE.md), offer a one-off backfill
   pass over those artefacts; when the user names a finished session, run
   the same pass scoped to it. Entries cite the durable artefact (file and
   section) in `session_context`, never a session. Procedure:
   `references/environments.md` ("First-run backfill").

## When to Observe

Active for the entire task session — execution, post-task feedback, review
discussion, meta-discussion about skills or methodology, and strategy
conversations about how work should be done. **The observation mindset
does not deactivate when the conversation shifts from doing the work to
discussing it**; review-phase feedback is often the highest-signal input.
Inactive only for casual conversation and tool-free factual questions.

## What to Watch For

**New skill:** a reusable multi-step workflow, a methodology the user
explains that no skill captures, a recurring task type, a process the user
describes as "I always do it this way". **Improve a skill:** the agent
violates a documented rule (the skill needs enforcement, not louder rules);
a user correction reveals a missing rule or edge case; a better workflow or
technique emerges than the skill recommends; a wrong assumption; new
tooling obsoletes a step; a principle that applies to other skills too.
**Simplify a skill:** a section never relevant across many sessions, a rule
from a single unvalidated observation, contradictory rules, a rule the
agent consistently fails to follow — convert to structural enforcement or
remove. Full catalogue with examples: `references/signals.md`.

**An unresolved defect is an observation, at a bounded point.** When a
defect that is not itself the deliverable takes a second hypothesis, load
`references/signals.md` ("An unresolved defect is an observation, at a
bounded point") and log the evidenced problem report, not a fifth probe.

**Do NOT log:** one-off corrections that don't generalise; preferences
already captured in a skill; tool bugs unrelated to methodology;
observations needing proprietary client information to be useful in an
open-source skill (unless an internal skill is the right home). When
unsure, run `references/signals.md` ("The generalisability test"): mostly
no → task context, not an observation. Before minting a `proposes_skill`
name, reuse a fitting existing candidate — independently logged proposals
for one skill rarely share a name.

**Check for a restatement before writing.** Before creating the file, list
the open observations that name the same target skill (the scan at session
start already holds their titles; otherwise `find observation-log -name
'*.md' -exec grep -l -E "^(skill|target_file):.*<bare-name>" {} +`) and read those titles. If the
finding is the same one restated — the same rule, the same failure shape, a
different example — extend the existing entry instead: append the new
instance to its body, add the session to `session_context`, widen `title:`
to cover it. Duplication is only visible in aggregate, and a near-duplicate
costs a capture every session and a triage every review.

**Validate the target at write time.** `skill:` names a skill that exists
now and performs the operation the Issue describes, written as its bare
name (`plugin:name` only where two skills share it). If the right home is
not a skill — an instructions file, a memory note, the register a routine
reads — put that path in `target_file:`; a skill not yet built goes in `proposes_skill:`.

**Check the target's siblings at write time, and record that you did.**
Before writing, resolve the target against the family registry
(`skill-observations/skill-families.md`) and for each sibling either add it
to `skill:` or say in the body why it does not apply. Fast test: **could
this sentence survive having the tool's or subject's name removed?** If
yes it belongs to every sibling. Record the outcome in the mandatory
`siblings_checked:` field, including the verdict "checked —
instance-specific, no propagation": a one-entry `skill:` list looks the same
whether the siblings were evaluated or never considered, and only the
recorded field makes the *absence* of the judgement visible.
Load `references/observation-log.md` ("Skill families and the sibling
check") for the registry spec, the coherence models and the fallback when
no registry exists.

**Log your own rule violations.** Breaking a rule that a skill or a project
instruction file documents is a first-class observation, not an
embarrassment to move past: it is the only evidence that the rule's
*enforcement* is too weak, and nobody but the agent can see it. Log it in
the same turn, and name which protection was actually in play — written
down, loaded into context, or backed by a checkpoint; the restatement check
above surfaces the earlier entry, so the count arrives without extra work.

**Second violation of the same rule: stop proposing text.** A rule that has
failed twice with no intervening `actioned` fix has a protection problem,
not a wording problem. From the second occurrence the proposed improvement
must be a structural barrier — a hook that refuses the call, a lint rule, a
default that makes the wrong path unavailable — never a clearer sentence, a
bolder warning, or the same rule moved somewhere more prominent. Load
`references/signals.md` ("Second violation — why a barrier, not a
rewording") before proposing either.

## How to Log

Write the observation file **within the same turn or the next, without
interrupting the user's task** — never batch mentally for later; the act
of writing is the enforcement mechanism.

**Mandatory checkpoint after every 3rd completed todo item.** After marking
the 3rd, 6th, 9th (etc.) item complete you must **write to disk** — not
merely ask yourself whether anything is pending. Write any pending
observation files, or append a one-line `no observations` acknowledgement
to `skill-observations/checkpoints.log`: a remembered "ask whether" is not
enforcement. Roughly every third completion is the rule. (Exception for a
priced-write workspace: `references/environments.md`.)

**A denied or failed write is not a read-only log.** A transient failure
(an I/O error, a timeout, a tool error with no permission decision) gets
one retry. A permission or classifier denial is authoritative: tell the
user in one line what was denied and why the write mattered, then carry
the observations in report-back or handoff mode (`references/environments.md`).
A classifier denial gets at most one identical retry, told to the user as a
check for a false negative — never a different tool. A mode that refuses
every write by design is neither: defer, don't retry
(`references/environments.md`, "A mode that forbids every write by design").

**Deliverable-event flush.** Whenever a unit of work is declared complete
to a human — a file handed over, a render, a staged skill file, a
completion notification, a final report, a finished todo batch — write any
pending observation files at that moment; the flush rides on a tool call
you were making anyway. (Why both checkpoints are writes rather than
questions, and why a finding met while resolving another observation gets
its own file: `references/observation-log.md`.)

**A failed write to an external system is a flush trigger in its own
right** — a tool result carrying `permission stream closed`, `permission
denied`, or a harness interrupt. Not a completion, but it has both
properties the flush needs: it is a literal string in the tool record
rather than a judgement about whether the moment qualifies, and it lands
where a run has just found something worth reporting and is most likely to
stop instead. Flush before doing anything else with the failure, including
deciding what to do about it (observed: an unattended run took a permission
error on its first external write and ended with no report and no entry).

**Two gaps this pairing still leaves:** the 3rd-completion checkpoint is
inert without todos, and "is this a major deliverable?" is a self-assessment
— so a chat-only session has no trigger unless the harness supplies one (a
turn-end hook). Before adding or changing any enforcement trigger, load `references/observation-log.md`
("Two gaps the checkpoint pairing still leaves — and the rule behind both").

**Id and filename.** Each observation is `NNNN-short-slug.md` (zero-padded
id + a kebab-case slug from the title). The id is the highest of three
values, plus one: the highest numeric prefix in `observation-log/`, the
highest in `observation-log/archive/`, and the number in
`observation-log/archive/.id-floor` (the highest id ever issued — update it
whenever you issue an id above it, so the counter can never restart from 1
when the active directory is empty). The same command first sweeps stale
resolved files into `archive/` — archival is a side effect of deriving the
id, not a separate duty (see Archival on Write):

```bash
d="[ABSOLUTE PATH]/skill-observations/observation-log"   # the pinned workspace path, never relative to the cwd; it may contain a space, so keep it quoted; bash, not sh
today=$(date +%F)          # archival rides inside this command (see below):
n_files=$(find "$d" -maxdepth 1 -name '[0-9]*.md' ! -empty | wc -l | tr -d ' ')   # a zero-byte file gives awk no line to count
seen=$(cd "$d" && awk 'FNR==1 {n++; nextfile} END {print n+0}' [0-9]*.md 2>/dev/null)   # files the sweep's glob reaches, counted apart from the sweep
[ "$n_files" -gt 0 ] && [ "${seen:-0}" -eq 0 ] && { echo "ARCHIVAL SWEEP BROKEN — $n_files files present, 0 examined"; exit 1; }
( cd "$d" && LC_ALL=C awk -v today="$today" 'FNR==1 {st=""; r=""; sub(/^\357\273\277/, ""); fm=/^---[[:space:]]*$/; if (!fm) nextfile; next}
    fm && /^---[[:space:]]*$/ {if (st ~ /^(actioned|declined|superseded)$/ && r ~ /^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$/ && r < today) print FILENAME; nextfile}
    fm && /^status:/ {st=$ 2}   # spaced on purpose: a skill load with arguments rewrites a digit right after $ (validator warns)
    fm && /^resolved:/ {r=$ 2}' [0-9]*.md 2>/dev/null | while IFS= read -r x; do mv -n "$x" archive/ 2>/dev/null; if [ -e "$x" ]; then echo "NOTE: $x not archived — archive/$x exists or the move failed"; fi; done )   # one awk for the set, one mv per stale resolved file, never over an archived one; bash
floor=$(sed '1!d; s/[^0-9]//g' "$d/archive/.id-floor" 2>/dev/null); floor=$((10#${floor:-0}))   # digits only: a CRLF or padded floor still reads
ids=$(for p in "$d"/[0-9]*.md "$d"/archive/[0-9]*.md; do [ -e "$p" ] && printf '%s\n' "${p##*/}"; done | grep -oE '^[0-9]+')   # globs and builtins: no `ls` a profile alias can rebind
[ "$(printf '%s' "$ids" | grep -c .)" -eq "$(find "$d" "$d/archive" -maxdepth 1 -name '[0-9]*.md' | wc -l)" ] || { echo "ID COMMAND BROKEN — the listing and find disagree on the prefixed files"; exit 1; }
hi=$(printf '%s\n' "$ids" | sort -n | tail -1); hi=$((10#${hi:-0}))   # from the files alone; 10#: a zero-padded prefix is not octal
[ "$hi" -lt "$floor" ] && echo "NOTE: highest file id $hi is below .id-floor $floor — ids issued without a file; the new id goes above the floor"
next_id=$(( (hi > floor ? hi : floor) + 1 ))      # never below the floor, whatever the listing saw
f="$d/$(printf '%04d' "$next_id")-<slug>.md"      # the target path, built from the id just derived
[ -n "$(find "$d" -maxdepth 2 -name "$(printf '%04d' "$next_id")-*.md")" ] && { echo "COLLISION — id $next_id already used; re-derive"; exit 1; }   # guard the id PREFIX across active + archive, not the path
(set -C; : > "$f") || exit 1                        # noclobber: create, never truncate an existing file
printf '%s\n' "$next_id" > "$d/archive/.id-floor"   # AFTER the create: an id check that writes no file never moves the floor
```

The listing guard tells "the log says zero" from "I could not read
the log", the sweep's count does the same for the archival loop, the prefix
guard refuses a number already in use under any slug, and the `noclobber`
create refuses an existing path — write the body only after that create
succeeds, with the editing tool, or a QUOTED heredoc (never unquoted) where
commands arrive unaltered: `references/observation-log.md` ("Editing an existing observation").
Load `references/observation-log.md` ("The guard line, the sweep's count
and the noclobber create") when any of them fires.

**Run the snippet immediately before EVERY write, including the first and
only one of a session** — an earlier read of the log is not a substitute,
and the id the session-start scan printed is never an input to a write.
Where a helper can run, `bash scripts/new-observation.sh --body <file>
<slug> "[ABSOLUTE PATH]"` is the only write path: it runs this whole snippet,
copies the body in with `__ID__` and `__DATE__` filled and prints the created
path, so derivation cannot drift from creation. Load
`references/observation-log.md` ("Run the snippet immediately before every
write") when skipping feels reasonable.

**Resolve each id at its own write time** — run the snippet before EACH
file, never pre-compute a range, and put the value it printed into both the
filename and the `id:` field. Load `references/observation-log.md`
("Resolve each id at its own write time") before batching or parallelising.

**Every instrument gets the same guard: an empty or zero result is a
claim about the instrument until an independent probe shows the
population is empty.** Load `references/observation-log.md` ("Every
instrument gets the same guard") before writing any new scan, count, grep
or query over the log.

**A structural probe that comes back empty where content existed before is
a stop signal, not a create** — HALT and re-probe; never let an append
recreate a missing target. Load `references/observation-log.md` ("A
structural probe that comes back empty is a stop signal") before writing
anything after such a probe.

**File format.** YAML frontmatter (the metadata every scan reads) followed
by the Issue → Improvement → Principle body. **The frontmatter is mandatory;
always write `status: open` and a non-empty `siblings_checked:` at creation
time** — an observation without a `status` field is treated as OPEN by
reviews, never as nonexistent, and one without `siblings_checked:` counts
as logged without a sibling check.

```markdown
---
id: 0
title: "Short descriptive title"
status: open            # open | actioned | declined | superseded | parked
type: open-source       # open-source | internal
skill: [skill-a, skill-b]        # existing skills this improves — always a
                                 # list, first entry primary, may be empty: []
proposes_skill: []               # new skills this argues for, by working
                                 # name; either list or both may be filled
target_file: []                  # when the right home is n...

© Eoghan Henn and contributors · CC-BY-4.0 · rebelytics/one-skill-to-rule-them-all

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor