diff --git a/README.md b/README.md index a07ab90..f86a673 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,8 @@ flowchart LR org --> org_coordinate[kvb-org-coordinate] org --> org_perform[kvb-org-perform] org --> org_matrix[kvb-org-matrix] + org --> org_rasci[kvb-org-rasci] + org --> org_artefacts[kvb-org-artefacts] org --> org_robot[kvb-org-robot] skills --> skills_dream[kvb-skills-dream] skills --> skills_tune[kvb-skills-tune] @@ -124,6 +126,8 @@ flowchart LR coordinate[kvb-org-coordinate] subagent_model[kvb-org-perform] status_matrix[kvb-org-matrix] + rasci[kvb-org-rasci] + artefacts[kvb-org-artefacts] robot[kvb-org-robot] end subgraph cat_skills [skills] @@ -167,6 +171,12 @@ flowchart LR funnel --> subagent_model dialectic --> subagent_model democracy --> merge_fix + democracy -. claim and release .-> rasci + funnel --> rasci + status_matrix --> rasci + cleanup --> artefacts + artefacts --> rasci + dream --> rasci observe --> triage observe --> ci_artifacts diff --git a/skills/kvb-check-principles/SKILL.md b/skills/kvb-check-principles/SKILL.md index 53041af..fb5f434 100644 --- a/skills/kvb-check-principles/SKILL.md +++ b/skills/kvb-check-principles/SKILL.md @@ -1,10 +1,10 @@ --- name: kvb-check-principles description: > - Analyse a repository, path or diff with a hostile eye for violated - principles: SPOT, DRY, KISS, SRP, security at trust boundaries. Trigger on - /kvb-check-principles, "sei skeptisch", "kritische analyse", "review the architecture", - or "what is wrong with the code". + Analyse a repository, path or diff for violated principles: SPOT, DRY, KISS, + SRP, security at trust boundaries. Trigger on /kvb-check-principles, "sei + skeptisch", "kritische analyse", "review the architecture", or "what is + wrong with the code". --- The stance is adversarial: the code is guilty until its structure proves diff --git a/skills/kvb-ci-triage/SKILL.md b/skills/kvb-ci-triage/SKILL.md index 7debe12..d4370e0 100644 --- a/skills/kvb-ci-triage/SKILL.md +++ b/skills/kvb-ci-triage/SKILL.md @@ -40,7 +40,9 @@ jobs' logs, and a first clustering. The judgement in those steps stays yours. 3. **Coordinate every cluster.** Run the `kvb-org-organize` skill's Lineage and Peer protocol for each cluster before fixing it: claim it, ask the lineage whether someone already fixes it, and take their fix or keep yours. Keep - investigating while you wait for answers. + investigating while you wait for answers. In the `kvb-org-rasci` register + the cluster's objective is the root cause fixed, its key results are the + failing jobs passing again, one per job. 4. **Download artifacts per cluster.** Use the `kvb-ci-artifacts` skill for the mechanics — it covers per-job logs while a run is still in progress, which bundle to pull, and the grep hygiene that keeps a false positive from diff --git a/skills/kvb-cleanup/SKILL.md b/skills/kvb-cleanup/SKILL.md index bf7134b..5c4bd8b 100644 --- a/skills/kvb-cleanup/SKILL.md +++ b/skills/kvb-cleanup/SKILL.md @@ -1,7 +1,7 @@ --- name: kvb-cleanup description: > - Free disk space agents filled: ask peer sessions what they still need, + Free disk space agents filled: ask peers what they still need, inventory /tmp, Docker and agent dirs, and delete only what the operator picks. Trigger on /kvb-cleanup, "aufräumen", "bereinigen", "platte voll", "no space left on device". @@ -60,6 +60,9 @@ Read-only, in parallel, sizes included: gh, buildx), worktrees with `git status --short` and whether their branch is merged or pushed, Ansible and build temp dirs. With `pkgmgr` installed, merged branches and worktrees go to the `kvb-git-branch-gc` skill instead. +- **Register**: `rasci.py artifacts` of the `kvb-org-artefacts` skill: + workdir, branch and artifacts of every task in the `kvb-org-rasci` register, + with its status and worker; `--ended` narrows it to the candidates. - **Live use**: open handles (`fuser`, `lsof`) and running processes by name only (`ps -o pid,etime,comm`). Never print full command lines or environments: process arguments carry credentials. A sandboxed agent often @@ -81,12 +84,15 @@ worktree or compose project name, a container label, an open handle, or `unknown`. Then apply, first match wins: 1. Claimed by a peer: `keep`. -2. A job running on it (deploy, gate, test, swarm run, build): `keep +2. Listed in the register under a task that is not `done`, `stopped` or `stale`: + `keep (task )`. Under an ended task it is a candidate whose owner is + the task's worker. +3. A job running on it (deploy, gate, test, swarm run, build): `keep (running)`. -3. Attributable to a peer that has not answered: `keep (no answer from +4. Attributable to a peer that has not answered: `keep (no answer from )`. Silence is not consent. -4. Archive duty: `archive first`. -5. Everything else is a candidate with a risk class: +5. Archive duty: `archive first`. +6. Everything else is a candidate with a risk class: | Risk | Meaning | Typical items | | ---- | ------- | ------------- | @@ -157,6 +163,8 @@ ticked items. Revise repeats call 1; nothing is deleted before `Execute`. - Idle running stacks go down through the project's teardown target, never by removing their containers or volumes underneath them. - Archive-first items: copy out, verify the copy, then delete. +- Drop every deleted item from its task as the `kvb-org-artefacts` skill + says (`set --drop-artifact :`), so `artifacts` stays true. - A delete failing on permissions (files owned by a container UID): use the project's container helper. Never sudo, never bypass the sandbox; without a helper, report the path. diff --git a/skills/kvb-code-test/SKILL.md b/skills/kvb-code-test/SKILL.md index 296d01d..66be662 100644 --- a/skills/kvb-code-test/SKILL.md +++ b/skills/kvb-code-test/SKILL.md @@ -2,7 +2,7 @@ name: kvb-code-test description: > Discover the Makefile's test targets, let the operator pick, run and report; - fix mode loops until green. Trigger on /kvb-code-test, /kvb-code-test --fix, or when the + fix mode loops until green. Trigger on /kvb-code-test [--fix], or when the operator asks to run the tests, make them pass, or get the suite green. --- diff --git a/skills/kvb-code-tune/SKILL.md b/skills/kvb-code-tune/SKILL.md index a995c8d..e38bce3 100644 --- a/skills/kvb-code-tune/SKILL.md +++ b/skills/kvb-code-tune/SKILL.md @@ -2,8 +2,8 @@ name: kvb-code-tune description: > Find and apply performance optimizations (CI, deploy, build, gate, hot - paths) without reducing logic, coverage or correctness. Trigger on /kvb-code-tune, - when a job dies on its time budget, when a pipeline or deploy grows slower, + paths) without reducing logic, coverage or correctness. Trigger on + /kvb-code-tune, a job dying on its time budget, a slower pipeline or deploy, or asked where time goes. --- @@ -113,7 +113,9 @@ every agent session on this machine, not only the branch lineage. - **The first to identify a cluster works it.** "First" is the `kvb-org-organize` claim `cluster/`, whose `--work` names the cluster's log line and number; between machines, the earliest announcement by message time. A - claim without a measurement does not count. + claim without a measurement does not count. In the `kvb-org-rasci` register + the cluster's key result is the measured target (` from to + under `), met only by the re-measurement. - **Someone was earlier:** send them your measurements and findings, then move on to the next cluster. Never build a second optimization of the same cluster. diff --git a/skills/kvb-create-feature/SKILL.md b/skills/kvb-create-feature/SKILL.md index a3922c5..41a50ff 100644 --- a/skills/kvb-create-feature/SKILL.md +++ b/skills/kvb-create-feature/SKILL.md @@ -2,9 +2,9 @@ name: kvb-create-feature description: > Derive missing work (principles pass for structural flaws, usability pass for - missing features) and write requirement documents after single-select - confirmation. Trigger on /kvb-create-feature, "was fehlt noch", "welche features - brauchen wir", or when the operator asks what to build next. + missing features) and write requirement documents after confirmation. + Trigger on /kvb-create-feature, "was fehlt noch", "welche features brauchen + wir", or asked what to build next. --- Two blind spots produce different work: the code has defects of structure, diff --git a/skills/kvb-create-plan/SKILL.md b/skills/kvb-create-plan/SKILL.md index 8db26d3..446b1fe 100644 --- a/skills/kvb-create-plan/SKILL.md +++ b/skills/kvb-create-plan/SKILL.md @@ -30,9 +30,11 @@ verified, and an unverifiable plan cannot be handed to a robot. trade-off the plan rests on gets settled before execution, escalating to the `kvb-think-dialectic` skill where being wrong is expensive. The robot does not ask, so an unresolved decision becomes a guess at runtime. -6. **Record the plan as a todo list.** Write the sub-objectives into the - harness's own todo tracking, one entry per item, phrased as the outcome. Keep - a plan file only when the operator asks for one. +6. **Record the plan in the register.** Enter the objective in the + `kvb-org-rasci` register with each sub-objective's verification as a key + result, and mirror the sub-objectives into the harness's own todo tracking, + one entry per item, phrased as the outcome. Keep a plan file only when the + operator asks for one. 7. **Present it and wait.** Show the objective, the ordered sub-objectives with their verifications, what is deliberately out of scope, and the assumptions the plan rests on. Stop here: the plan is the deliverable of this step. diff --git a/skills/kvb-git-branch-gc/SKILL.md b/skills/kvb-git-branch-gc/SKILL.md index 6c288f1..d36f996 100644 --- a/skills/kvb-git-branch-gc/SKILL.md +++ b/skills/kvb-git-branch-gc/SKILL.md @@ -81,6 +81,10 @@ Then ask with `AskUserQuestion`: (still in use elsewhere), or `failed: `. Report a failure as it stands; never remove by hand what gc skipped or refused. +4. For every `done` item, drop its worktree and branch from the task that + lists them in the `kvb-org-rasci` register (`rasci.py artifacts` names + it): `set --drop-artifact worktree:`, and `--branch ''` where + the branch is gone. ## Step 5: unmerged and dirty diff --git a/skills/kvb-org-artefacts/SKILL.md b/skills/kvb-org-artefacts/SKILL.md new file mode 100644 index 0000000..64af104 --- /dev/null +++ b/skills/kvb-org-artefacts/SKILL.md @@ -0,0 +1,31 @@ +--- +name: kvb-org-artefacts +description: > + Artifacts of the kvb-org-rasci register per task: images, volumes, + worktrees. Trigger on /kvb-org-artefacts, "artefakte". +--- + +Artifacts live in the same table as the tasks of the `kvb-org-rasci` +register: each one belongs to exactly one task, carries its kind, reference +and the time it was recorded, and takes status and worker from its task. The +script is the register's `${CLAUDE_SKILL_DIR}/../kvb-org-rasci/scripts/rasci.py`. + +```bash +rasci.py set --artifact : +rasci.py set --drop-artifact : +rasci.py artifacts [--ended] [--task ] +``` + +Kinds: `image:`, `container:`, `volume:`, `network:`, `stack:`, `worktree:`, +`dir:`, `log:`. `artifacts` lists each task's workdir and branch beside them. + +## Rules + +- Record an artifact the moment it exists, under the task that created it; + one left unrecorded is invisible to cleanup. +- `artifacts --ended` lists what belongs to `done`, `stopped` or `stale` + tasks: the cleanup candidates, owned by the task's worker. Everything of an + open task stays. +- Deleting goes through the `kvb-cleanup` skill, where the operator picks; + drop the artifact here once it is gone. +- The register's `show` counts each task's artifacts in its Artifacts column. diff --git a/skills/kvb-org-coordinate/SKILL.md b/skills/kvb-org-coordinate/SKILL.md index 9219ca4..7d1f103 100644 --- a/skills/kvb-org-coordinate/SKILL.md +++ b/skills/kvb-org-coordinate/SKILL.md @@ -7,5 +7,6 @@ description: > --- Run the `kvb-org-organize` skill's **Lineage** and **Peer protocol** sections for the -failure or fix at hand. They hold the whole procedure; this skill only keeps -`/kvb-org-coordinate` working. +failure or fix at hand. They hold the whole procedure, including the entries +in the `kvb-org-rasci` register; this skill only keeps `/kvb-org-coordinate` +working. diff --git a/skills/kvb-org-matrix/SKILL.md b/skills/kvb-org-matrix/SKILL.md index 9947a7a..b512ff9 100644 --- a/skills/kvb-org-matrix/SKILL.md +++ b/skills/kvb-org-matrix/SKILL.md @@ -15,7 +15,7 @@ decides what to act on after reading the matrix. Gather in parallel, skip any source the session does not have, and never invent a row for a source you could not read: -1. **Tasks** — the session's todo list, the operator's stated goals this +1. **Tasks** — the `kvb-org-rasci` register first, then the session's todo list, the operator's stated goals this session, and any requirement or plan documents the work follows. 2. **Working tree** — `git status --short` and `git log --oneline -10`: uncommitted files are open work, commits since the branch point are closed diff --git a/skills/kvb-org-organize/SKILL.md b/skills/kvb-org-organize/SKILL.md index 78062b7..40a81d5 100644 --- a/skills/kvb-org-organize/SKILL.md +++ b/skills/kvb-org-organize/SKILL.md @@ -53,8 +53,10 @@ directory with `--session `. worktree>"`. Exit 0: elected, or already yours. Exit 3: a live agent holds it, and its claim is printed. Exit 4: the holder's session is dead (see Succession). -4. **Elected**: continue with the Peer protocol; its message is the - announcement. +4. **Elected**: the claim entered the task in the `kvb-org-rasci` register, + the organisation's single point of truth; complete it there (objective, + description, priority, roles), then continue with the Peer protocol; its + message is the announcement. 5. **Not elected**: send the holder your findings and stop on that work. A Claude Code session cannot edit a file in a git worktree before it holds a @@ -74,8 +76,9 @@ records the result. - Before starting anything that consumes shared capacity (gates, deploys, iteration loops, swarm or cloud resources, cleanup of shared data), an agent sends the chair what, where, for how long and its expected disk need, waits - for the grant, and reports the release. The chair keeps one queue, answers - every request with its position, enforces the limits the operator set, + for the grant, and reports the release. The chair keeps one queue as the + priorities in the `kvb-org-rasci` register, answers every request with its + position, enforces the limits the operator set, checks every grant with `watch.py admit --need-gb ` (or `--kind `; test kinds also need CPU and RAM below the configured limits). - A running job (deploy, gate, test, swarm run, build) is never cut short to @@ -154,14 +157,18 @@ The one protocol for every exchange between agents; `kvb-org-coordinate`, `kvb-c evidence (failing line quoted literally, run id, measurement), the suspected cause marked as a thesis, and the question "Already known or fixed on your side? Reply with a SHA or branch, or 'none'." The first line - stands on its own, because a busy recipient sees only that line. + stands on its own, because a busy recipient sees only that line. In the + `kvb-org-rasci` register the peers asked are C, the chair that grants + capacity is S. 4. **Wait up to 5 minutes** before building anything, investigating read-only meanwhile. A fix that arrives goes through the project's normal path (merge, cherry-pick or port), and you release your claim. Silence is neither a "no" nor a competing claim: after 5 minutes, proceed. 5. **Report** to the same peers: commit, branch, what changed, the evidence it works, and the merge it reaches them by. Report an abandoned or failed - attempt too. Then release the claim. + attempt too. In the register, enter the peers told as I and mark every key + result the evidence proves as met. Then release the claim: the task ends + `done`, or `stopped` while a key result is open. - Never invent a peer's answer. - A peer's report is not evidence: read the SHA, log or artifact it names @@ -199,3 +206,6 @@ On /kvb-org-organize, one table of the current offices from `council.py list`, s claims marked: | Office | Holder | Since | Work | Grants or queue | + +Who carries which task, with priority and status, is the `kvb-org-rasci` +register's `show`. diff --git a/skills/kvb-org-organize/scripts/council.py b/skills/kvb-org-organize/scripts/council.py index 11dd8a7..94c0ade 100755 --- a/skills/kvb-org-organize/scripts/council.py +++ b/skills/kvb-org-organize/scripts/council.py @@ -16,10 +16,12 @@ from __future__ import annotations import argparse import datetime +import importlib.util import json import os import re import shutil +import subprocess import sys import time from pathlib import Path @@ -28,6 +30,7 @@ ROOT = Path(os.environ.get("AGENTS_COUNCIL_ROOT", "/tmp/agents-council")) HEARTBEAT_LIMIT = 3600 OFFICE = re.compile(r"^[a-z0-9][a-z0-9._-]*(/[a-z0-9][a-z0-9._-]*)*$") CLAIM = "claim.json" +RASCI = Path(__file__).resolve().parents[2] / "kvb-org-rasci" / "scripts" / "rasci.py" def live_sessions() -> dict[str, str | None]: @@ -83,7 +86,7 @@ def claims() -> list[tuple[str, dict]]: return found -def write_claim(path: Path, office: str, sid: str, runtime: str, work: str) -> None: +def write_claim(path: Path, office: str, sid: str, runtime: str, work: str) -> dict: claim = { "office": office, "session": sid, @@ -94,6 +97,30 @@ def write_claim(path: Path, office: str, sid: str, runtime: str, work: str) -> N "work": work, } (path / CLAIM).write_text(json.dumps(claim), encoding="utf-8") + return claim + + +def here() -> dict[str, str | None]: + try: + head = subprocess.run( + ["git", "rev-parse", "--abbrev-ref", "HEAD"], capture_output=True, text=True, check=False + ) + except OSError: + head = None + branch = head.stdout.strip() if head and head.returncode == 0 else "" + return {"workdir": os.getcwd(), "branch": branch if branch not in ("", "HEAD") else None} + + +def register(office: str, holder: str, status: str, **extra: str | None) -> None: + if not office.startswith(("work/", "cluster/")): + return + try: + spec = importlib.util.spec_from_file_location("rasci", RASCI) + rasci = importlib.util.module_from_spec(spec) + spec.loader.exec_module(rasci) + rasci.track(office, holder, status, **extra) + except (OSError, SystemExit) as exc: + print(f"council: {office} is missing from the rasci register ({exc})", file=sys.stderr) def cmd_claim(args: argparse.Namespace) -> int: @@ -105,12 +132,21 @@ def cmd_claim(args: argparse.Namespace) -> int: except FileExistsError: claim = read_claim(path) if claim is not None and claim["session"] == sid: - write_claim(path, args.office, sid, runtime, args.work) + claim = write_claim(path, args.office, sid, runtime, args.work) + register(args.office, claim["name"] or sid, "running", description=args.work, **here()) print(f"held {args.office}") return 0 print(json.dumps(claim) if claim else f"{args.office}: claim in progress") return 4 if is_stale(claim, live_sessions()) else 3 - write_claim(path, args.office, sid, runtime, args.work) + claim = write_claim(path, args.office, sid, runtime, args.work) + register( + args.office, + claim["name"] or sid, + "running", + description=args.work, + previous=getattr(args, "previous", None), + **here(), + ) print(f"elected {args.office}") return 0 @@ -121,6 +157,8 @@ def cmd_takeover(args: argparse.Namespace) -> int: if path.exists() and not is_stale(claim, live_sessions()): print(json.dumps(claim) if claim else f"{args.office}: claim in progress") return 3 + if claim is not None: + args.previous = claim["name"] or claim["session"] # Two successors racing between this check and the rename can both win; # kvb-org-organize names exactly one successor per office to keep that window closed. if path.exists(): @@ -145,6 +183,7 @@ def cmd_release(args: argparse.Namespace) -> int: print(json.dumps(claim)) return 3 shutil.rmtree(path) + register(args.office, claim["name"] or claim["session"], "done") print(f"released {args.office}") return 0 diff --git a/skills/kvb-org-perform/SKILL.md b/skills/kvb-org-perform/SKILL.md index 679b8f5..a552360 100644 --- a/skills/kvb-org-perform/SKILL.md +++ b/skills/kvb-org-perform/SKILL.md @@ -31,6 +31,8 @@ Fable 5.1 $10 / $50. 2. Start the brief with the line `task-class: `; the spawn hook logs it together with `model`, `effort` and the Agent `description`. 3. Set `model` and `effort` from the row; for `judgement` set neither. +4. Enter the spawn in the `kvb-org-rasci` register: the subagent as R and as + `--worker "subagent (, )"` of the task it serves. - An agent type whose definition sets its own model (Explore, Plan, the cavecrew agents) keeps it; never pass `model` or `effort` for it. diff --git a/skills/kvb-org-rasci/SKILL.md b/skills/kvb-org-rasci/SKILL.md new file mode 100644 index 0000000..9ecd6db --- /dev/null +++ b/skills/kvb-org-rasci/SKILL.md @@ -0,0 +1,60 @@ +--- +name: kvb-org-rasci +description: > + RASCI/OKR register of tasks: roles, key results, worker, status. + Trigger on /kvb-org-rasci, "rasci", "raci", "zuständigkeiten". +--- + +The register is the single point of truth of the organisation: every agent +records here what it works on, and claims, queue, handover and reports run +over it. `${CLAUDE_SKILL_DIR}/scripts/rasci.py` keeps it in +`/rasci.json`. A `kvb-org-organize` claim enters its task by +itself (holder as R and A, `running`, start, workdir, branch); its release +sets `done` and the end, or `stopped` while a key result is still open. + +```bash +rasci.py set --title --objective --description --prio --status queued|running|blocked|done|stopped --worker " ()>" --workdir --branch --artifact : --tool