# Repo-scoped automation review CLI (`activity`) **Status:** implemented (ACTIVITY-WP-0028) — v1 shipped 2026-08-06 **CLI name:** `activity` **Related:** [runbook.md](runbook.md), [ops-run-queue.md](ops-run-queue.md), [recurring-automations-playbook.md](recurring-automations-playbook.md), [edge-relay-resilience.md](edge-relay-resilience.md), [llm-connect-host-access.md](llm-connect-host-access.md) **Origin:** Freedom Intelligence operator need (2026-08-06) — review scheduled deliverables from the consumer repo without AI tooling. --- ## Rigorous review of the original concept ### What is strong (keep) | Strength | Why it matters | | -------- | -------------- | | **Repo-first lens** | Operators live in consumer repos; org-wide `automation-status` is the wrong default UX for “did FI run?” | | **Multi-source truth** | Git vs hub vs ops_run disagreement is real (FI 2026-08-06: brief on origin, hub event lag). Single-source answers mislead. | | **Local checkpoint / ack** | “Since I last looked” is personal; belongs in XDG state, not State Hub or actcore DB | | **Non-goals** | Not a scheduler, not an agent, not a workplan writer — keeps scope bounded | | **Reuse stack** | Ops API + artefacts (WP-0027) + git + hub progress — no new backend product | | **Exit codes for scripting** | Fits morning automation and CI-ish operator habits | ### What was weak or ambiguous (fix) | Issue | Optimization | | ----- | ------------ | | Name `actcore-review` | Prefer **`activity`** — short, repo-native, pairs with domain “activity definitions”. Document collision with unrelated packages; ship as console script of `activity-core`. | | Five overlapping verbs | Collapse to a **stable verb set** with clear precedence: `status` = compose; `list` / `runs` / `deliverables` / `inbox` = slices; `ack` / `checkpoint` = local state only | | “~100–200 lines wrapper” | Underestimates definition parsing, multi-source merge, and tests. Target a small **module package** under `activity_core/review_cli/` (~500–800 LOC + tests), not a one-file hack | | Deliverable globs unspecified | Require a **convention** in definition frontmatter or docs table; v1 ships FI + Binky built-ins + optional `review:` block | | Collection candidates first-class | **Defer** to v2 — regex mining briefs is fragile; path-level inbox first | | Exit code 3 always | **Opt-in** `--strict-review` only — default 0/1/2 keeps “green morning” scripts usable | | Live API always assumed | **Offline-first ladder**: local defs + git always work; API/hub enrich when reachable | | Checkpoint stores both commits and paths | Prefer **path + ops_run_id** as primary ack keys; commits are optional hints only (paths move less than SHAs across rebase) | | Prod SSH helper as first path | Prefer **ops API** (`ACTIVITY_CORE_URL` / SSO-reachable host); SSH prod script is break-glass only | ### Verdict **Concept is good.** Implement it as the **`activity` CLI**, activity-core owned, consumer-cwd friendly, offline-capable, multi-source honest. --- ## Problem (restated) From a **consumer repo** (e.g. `freedom-intelligence`), answer without AI: 1. Are regular automations declared / scheduled for this repo? 2. What is the list? 3. What ran or failed in a time window (today / week / since last review)? 4. What deliverables were produced? 5. What is still open for human review? Evidence is split today: activity-core definitions/runs/ops_runs, State Hub progress, git artefacts, ops UI. Existing tools are **activity-core-centric**, not **repo-first**, and lack a personal review cursor. ## Non-goals - New scheduler or claim worker - LLM / coding-agent workflow - Replacement for ops UI - Hub writes for workplans/tasks (checkpoint is local only) - Authoring definitions from the CLI - First-class “collection candidate” inbox items (v2) ## Name and entrypoint ```bash # Install (activity-core package) uv tool install -e ~/activity-core # or pip install -e . # → console script: activity cd ~/freedom-intelligence activity status activity inbox activity ack briefs/2026/08/2026-08-06.md ``` | Rule | Choice | | ---- | ------ | | Binary name | `activity` | | Package | `activity-core` (`[project.scripts] activity = activity_core.review_cli:main`) | | Default cwd | Consumer repo root (or any descendant) | | Repo slug | `--repo` > git remote path > `.repo-classification.yaml` > directory name | | Config | Named services in `~/.config/activity/services.json`; env still works | | Collision | If another `activity` is on PATH, use `python -m activity_core.review_cli` | ### Multi-service endpoints Operators may talk to more than one activity-core deployment (local stack, railiance, …). Configure named services once; pick a default; override per call. ```bash # userspace install make install-cli # register backends activity service add railiance \ --url https://activity.coulomb.social \ --hub-url http://127.0.0.1:18000 \ --description "Railiance prod (SSO)" \ --make-default activity service add local \ --url http://127.0.0.1:8010 \ --hub-url http://127.0.0.1:8000 activity service list activity service use local # switch default activity service which # what this shell would use # one-shot without changing default (flags after the verb) activity runs -s railiance --since today activity status --activity-url http://10.43.x.x:8010 ``` | Precedence (highest first) | Source | | -------------------------- | ------ | | 1 | `--activity-url` / `--hub-url` | | 2 | `--service NAME` / `-s NAME` | | 3 | `ACTIVITY_CORE_URL` / `STATE_HUB_URL` env | | 4 | config file default service | | 5 | unset (offline-only) | Config path: `${XDG_CONFIG_HOME:-~/.config}/activity/services.json` (or `ACTIVITY_CONFIG_DIR`). Working name `actcore-review` is **retired** in favour of `activity`. ## Commands | Command | Operator question | Evidence order | | ------- | ----------------- | -------------- | | `list` | What automations bind to this repo? | Local `activity-definitions/*.md` → ops API filter `target_repo` | | `runs [--since …]` | What ran / failed? | Ops API runs+ops_runs → hub `executor_run` → degraded label | | `deliverables [--since …]` | What was produced? | ops_run artefacts ∪ git globs ∪ hub completion paths | | `inbox` | Open for review? | Deliverables since checkpoint − ack set | | `status` | One-screen dashboard | Compose list + runs + inbox counts + source health | | `checkpoint show\|set\|clear` | Review cursor | Local state file only | | `ack ` | Mark reviewed | Updates local state; no remote writes | ### Defaults | Flag | Default | | ---- | ------- | | `--since` for `runs` / `deliverables` | `checkpoint` if set, else `today` (Europe/Berlin calendar day) | | `--since` shortcuts | `today`, `yesterday`, `week`, `sunday`, `checkpoint`, ISO date/time | | `--format` | `text` \| `json` | | `--strict-review` | off — when on, exit `3` if inbox non-empty | | `--repo` | auto-detect | ### Example session ```bash cd ~/freedom-intelligence && git pull --ff-only activity status # Repo: freedom-intelligence # Automations: 1 enabled (FI Daily Research Brief 30 7 * * 1-5 Europe/Berlin) # Since checkpoint 2026-08-05T16:00+02:00 # runs: 1 ok, 0 failed deliverables: 1 new inbox: 1 # Sources: defs=ok git=ok api=ok hub=degraded activity runs --since today # 2026-08-06 07:30 ok ops_run=… path=briefs/2026/08/2026-08-06.md hub=missing activity inbox # [ ] briefs/2026/08/2026-08-06.md (partial: git ok, hub fi_daily_brief missing) activity ack briefs/2026/08/2026-08-06.md activity checkpoint show ``` ### Exit codes | Code | Meaning | | ---- | ------- | | `0` | No automation failures in window; sources not hard-failed | | `1` | ≥1 failed run / failed ops_run in window | | `2` | Evidence degraded (API/hub unreachable; partial answer printed) | | `3` | Open inbox items remain (**only** with `--strict-review`) | ## Checkpoint model **Local, operator-owned** — XDG state, not hub/DB. ```text ${ACTIVITY_REVIEW_STATE_DIR:-$XDG_STATE_HOME/activity}//checkpoint.json # default XDG_STATE_HOME=~/.local/state ``` ```json { "repo": "freedom-intelligence", "schema": 1, "reviewed_at": "2026-08-05T16:00:00+02:00", "reviewed_paths": ["briefs/2026/08/2026-08-05.md"], "reviewed_ops_run_ids": ["eeccd98a-bd2b-4247-9289-2bf17aa22301"], "notes": "" } ``` - Primary ack keys: **`reviewed_paths`**, **`reviewed_ops_run_ids`** - `reviewed_at` advances on `ack` / `checkpoint set` - No multi-host sync (v1) ## Resolving “for this repo” 1. **Declared (offline):** parse consumer `activity-definitions/*.md` Match when `target_repo` == slug, or labels contain slug, or file lives in that repo’s definitions tree. 2. **Live schedule:** `GET /ops/automations?target_repo=` (add filter if missing). 3. **Runs:** `GET /ops/automations/{id}/runs?since=…` (artefacts from WP-0027); optional `GET /ops-runs?target_repo=&since=`. 4. **Deliverables:** union of artefact paths, git globs, hub completion `detail.path` for configured event types. ### Trust matrix (do not simplify away) | Git artefact | Hub completion | Interpretation | | ------------ | -------------- | -------------- | | present | present | **ok** | | present | missing | **partial** — produced; bookkeeping gap (warn, not “did not run”) | | missing | present | **lag/mismatch** — pull remote / wrong clone / path drift | | missing | missing | **missing** — did not run or failed before write | Never answer “did not run” from hub-only absence when git has the artefact. ## Definition convention (v1) Prefer optional frontmatter (when present): ```yaml review: deliverable_globs: - "briefs/**/*.md" completion_event_type: fi_daily_brief path_in_event: detail.path # default ``` **Built-in fallbacks** (no frontmatter required day one): | Repo / automation id | Globs | Completion event | | -------------------- | ----- | ---------------- | | `freedom-intelligence` / `fi-daily-research-brief` | `briefs/**/*.md` | `fi_daily_brief` | | `binky-control` / binky daily rhythm | `briefs/**/*daily*` | `binky_daily_brief` (if used) | Unknown automations: still list + show runs; deliverables only from `ops_run.result.path` when present. ## Placement | Layer | Role | | ----- | ---- | | `activity_core/review_cli/` | CLI + merge logic + checkpoint | | Ops API | `target_repo` filters; runs already carry artefacts | | `make activity-review …` | Thin Makefile pass-through (optional) | | Does **not** replace | `automation-list`, `automation-status`, `prod_automation_status.sh` | ## Architecture ```text activity status|list|runs|… │ ├─ resolve_repo(cwd, --repo) ├─ load_local_definitions() ├─ load_checkpoint(state_dir) ├─ try ops API (ACTIVITY_CORE_URL) ├─ try State Hub (STATE_HUB_URL) ├─ git log / path exists └─ merge → trust matrix → text|json + exit code ``` ### Minimal phases (implementation) | Phase | Deliverable | Offline? | | ----- | ----------- | -------- | | **P0** | `list` + `status` (defs only) + `--json` | yes | | **P1** | `deliverables` + `checkpoint` + `ack` + `inbox` (git + checkpoint) | yes | | **P2** | `runs` + hub completion join + trust matrix | partial | | **P3** | Live API `target_repo` filter + full green/partial rows | needs URL | | **P4** | Docs, Makefile, install path, FI morning ritual in playbook | — | ## Open decisions — locked for WP-0028 | # | Decision | Lock | | - | -------- | ---- | | 1 | Package location | **activity-core** console script `activity` | | 2 | Exit code 3 | **Opt-in** `--strict-review` | | 3 | Deliverable declaration | Optional `review:` frontmatter + built-in table | | 4 | Collection candidates | **Out of v1** | | 5 | Default evidence | Offline-first; API enriches | | 6 | Ack keys | paths + ops_run ids (not commits alone) | ## Relationship to existing tools | Tool | Role after `activity` ships | | ---- | --------------------------- | | `make automation-status` | Org/cluster window (unchanged) | | `prod_automation_status.sh` | Prod SSH fire counts (break-glass) | | ops UI | Browser review + trigger/pause | | **`activity`** | Consumer-repo morning review + personal checkpoint | ## Pin log | Date | Change | | ---- | ------ | | 2026-08-06 | Concept captured (actcore-review working name) | | 2026-08-06 | Rigorous review; rename to `activity`; optimize scope; WP-0028 |