# `notice` — Notice Board CLI

A small, stdlib-only Python CLI for Mission Control Notice Board, built
in the spirit of Printing Press: short commands, predictable flags,
optional JSON, audit log on writes, and no destructive defaults.

Since Plan 03 (schema v3.0), every mutator writes the new
`type` + `phase` + `sources` + `last_modified_at` fields and keeps the
embedded `item.link` sub-object in lockstep with the owning item's
phase/outcome. See `docs/notice-board-v3.md` for the full schema.

```bash
python3 /home/ananth/.hermes/mission-control-notice-board/tools/notice.py --help
```

## Commands

| command | purpose |
| --- | --- |
| `list` | List cards. Filter with `--status`, `--category`, `--tag`, `--query`; add `--json` for structured output. |
| `show ID` | Show one card by display id (includes lineage edges). |
| `capture TITLE --category CATEGORY [--type TYPE]` | Create a new Inbox item and append an audit entry. v3.0 defaults `type` from category (`Ideas`→`idea`, `Research`/`Learning`→`learning`, `Personal Admin`/`Dab Improvements`→`admin`, `Read`→`link`, `Uncategorized`→`note`); pass `--type` to override. Legacy `Research / Read` is silently migrated to `Research`. Refuses raw URLs into `--category Read`; use `link capture` instead. |
| `explore ID` | Move an item to Explore; optional `--intent`, `--next`, `--deadline`. Moving an Idea without `--next` prints a hint about the Ideas→Explore gate but does not block. |
| `next ID TEXT` | Set/update `next_action` on any item. |
| `done ID --outcome OUTCOME` | Mark Done with `completed`, `dropped`, `stale`, `archived`, `graduated`, or `read`; optional `--summary`. If the item carries an embedded `link` sub-object, its `link.status` is moved to the matching terminal state (`completed`/`read`→`read`, `dropped`→`dropped`, anything else→`archived`) in the same transaction. |
| `link capture URL [--title …] [--note …] [--source …] [--tag …]` | **Preferred raw-URL capture.** Creates a v3.0 item with `type=link`, embedded `link` sub-object at `link.status=unexplored`, and `category=Uncategorized`. A mirror entry is also written into the deprecated `link_triage[]` for one transition cycle. The Read page surfaces the item once `link.status` reaches `explainer_ready`. |
| `link add ID URL [--status …] [--note …]` | Attach a URL to an existing item by embedding/updating its `link` sub-object. The deprecated `link_triage[]` mirror row is written through. |
| `link status URL STATUS [--explainer …] [--note …]` | Transition the link. Allowed: `unexplored`, `explainer_ready`, `read`, `archived`, `dropped`. `needs_review` normalises to `unexplored`; legacy `promoted` → `archived`. Terminal statuses (`read`/`archived`/`dropped`) also promote the owning item to Done with the matching outcome, keeping `phase` / `outcome` / `link.status` in lockstep. |
| `link list [--status …] [--json]` | List Link Triage records (still reads the mirror; will switch to items[].link once the mirror is retired in plan 4+). |
| `set-explainer SLUG_OR_ID PATH [--written-at ISO] [--no-verify-path]` | Record that the explainer for a link item has been written to `PATH` (typically `items/<slug>/explainer.html`). Promotes `link.status` from `unexplored` → `explainer_ready`, lifts the item's `phase` from `inbox` → `explore` (and `status` Inbox → Explore), stamps `explainer_written_at`, and syncs the `link_triage[]` mirror. Used by the cron pass (plan 06); never sets the link to `read` (only the user does that). |
| `retype SLUG_OR_ID TYPE` | Change item `type` without touching its `category`. Types: `link`, `idea`, `learning`, `project`, `admin`, `note`. |
| `recategorize SLUG_OR_ID CATEGORY` | Change item `category` without touching its `type`. |
| `graduate SLUG_OR_ID` | **Plan 08 — graduation rail.** Mark an `idea` / `project` item as `Done/graduated`, default `template_fields.project_folder` to `~/AI/projects/<slug>/`, and queue a row in `pending_graduations[]` (`status: pending`). Idempotent — second runs are no-ops. The MacBook companion `scripts/mc_graduate_sync.py` (installed as `mc-graduate-sync`) materialises the actual folder. See `docs/graduation-rail.md`. |
| `ungraduate SLUG_OR_ID` | Reverse the Notice Board-side graduation: clears `outcome`, drops `template_fields.project_folder` and `graduated_at`, and removes any matching `pending_graduations[]` row. Does **NOT** delete `~/AI/projects/<slug>/`. |
| `confirm-graduation SLUG_OR_ID [--created-path PATH]` | Called by `mc-graduate-sync` after the local folder lands. Sets the matching `pending_graduations[]` row's `status` to `confirmed` and stamps `confirmed_at`; `--created-path` updates `template_fields.project_folder` to the actual MacBook path. |
| `relate ID_FROM TYPE ID_TO` | Add a lineage edge. Types: `parent_of`, `child_of`, `forked_from`, `related_to`, `merged_into`, `artifact_of`. |
| `auto-connect [--recent-hours N] [--all]` | Plan 07 auto-connect pass. Computes `suggested_relationships[]` for items modified in the last N hours (default 24, or `--all` for every item) using local TF-IDF over title + capture notes + explainer + tags + template fields. Mirrors each suggestion on the candidate side, then prunes any `suggested_relationships[]` older than 30 days. Re-runs `render.py` is not implicit — pair with `scripts/auto_connect_pass.py` for the cron variant. Tunable via `--threshold` (default 0.35) and `--top-k` (default 3). |
| `compute-suggestions SLUG_OR_ID [--threshold N] [--top-k N] [--via STR]` | Compute (and persist) suggested_relationships for a single item. Used by the cron pass for targeted re-suggestion after an explainer lands. |
| `connect SLUG OTHER_SLUG [--via auto\|manual]` | Promote a (pending) suggestion to a confirmed relationship on `item.relationships[]`. Mirrors on the partner item so both sides reference each other. Removes the matching `suggested_relationships[]` entry on both sides. `--via` defaults to the stored suggestion's via, or `manual`. |
| `dismiss-suggestion SLUG OTHER_SLUG` | Remove a pending suggestion from both sides without promoting it. No-op if neither side has the suggestion — designed to be safe to re-run. |
| `set-morning-brief JSON [--from-file PATH]` | **Plan 09 — morning brief writer.** Transactionally writes `brain.json.morning_brief` from the supplied JSON payload (must include `generated_at`). Used by `scripts/morning_brief_pass.py` to seed the prose summary the Notice Board renders at the top of Index. Pass `--from-file -` semantics via `--from-file PATH` to read the payload off disk. |
| `today` | Print the Today dashboard lanes (Link Triage queue, Inbox rot, Explore needing next-action) in text form. |
| `validate` | Run `scripts/validate_brain.py`. |
| `render` | Run `render.py` (writes `index.html`, `today.html`, `read.html`, `link-triage.html`, `timeline.html`, `search.html`, `analytics.html`). |
| `status` | Read-only git status. |
| `publish` | Dry-run only: prints git add/commit/push commands. |

## Safety

- No delete command; preserve history through Done outcomes.
- Mutating commands append to `inbox.md`.
- `publish` never commits or pushes.
- No external dependencies.
- No secrets or `.env` reads.

## Auto-connect (Plan 07)

Capture commands and `set-explainer` now compute TF-IDF suggestions in the
same transaction; failures are wrapped in `try/except` so capture itself
can never break. Pending suggestions surface in two places:

1. The "Suggested connections waiting" lane on `index.html` (counts plus
   the five most-recently-modified items).
2. The **Connections** section on each item page (under "Suggested"), with
   ready-to-copy `notice connect …` and `notice dismiss-suggestion …`
   commands.

The cron-runnable entry point is `scripts/auto_connect_pass.py`:

```bash
python3 /home/ananth/.hermes/mission-control-notice-board/scripts/auto_connect_pass.py            # last 24h + re-render
python3 .../auto_connect_pass.py --all                                                            # walk every item
python3 .../auto_connect_pass.py --recent-hours 6 --no-render                                     # tighter window, no render
```

`scripts/auto_connect_pass.py` shells out to `notice auto-connect`, which
performs the atomic mutation, and then runs `render.py` once at the end.
Pair it with the explainer cron pass: it adds ~10s per pass on the
current ~75-item corpus.

## Morning brief (Plan 09)

`scripts/morning_brief_pass.py` is the daily writer for the Morning
Brief block at the top of Index. It computes the same live sections the
renderer surfaces (new since yesterday, cron explained today, rotting)
and writes a short prose summary into `brain.morning_brief`:

```bash
python3 .../scripts/morning_brief_pass.py            # compute + write + render
python3 .../scripts/morning_brief_pass.py --dry-run  # print payload only
python3 .../scripts/morning_brief_pass.py --no-render
python3 .../scripts/morning_brief_pass.py --use-hermes  # try `hermes ask`, fall back to local
```

The default summary path is a deterministic, fully local string so the
pass never blocks on a network call and never opens an interactive
prompt. Passing `--use-hermes` attempts a short `hermes ask --no-tools`
call with a 60s ceiling and silently falls back to the local summary on
any failure. Schedule via the Hermes cron daemon or an equivalent — the
pass writes via `notice set-morning-brief`, so it cooperates with the
standard transaction lock.

The renderer marks the block stale (header pill + dimmed prose) when
`generated_at` is older than 25 hours; the live sections always reflect
current data regardless.

## Mission Control surfaces generated by `render`

| Page | Purpose |
| --- | --- |
| `index.html` | Notice Board (existing) — now with MC nav, decay badges, next-action lane, relationship chips. |
| `today.html` | Today dashboard — pending Link Triage, suggested merges, Inbox rot, Explore needing next-action, Read highlights, recent activity, Workflows summary. |
| `read.html` | Read queue (Option A) — explainer-ready / recently read / archived links, driven entirely by Link Triage. |
| `link-triage.html` | Active raw-link queue (`unexplored`) only. Routed links disappear from triage and surface on their destination page. |
| `timeline.html` | Activity grouped by date + lineage edges. |
| `search.html` | Client-side static search across items and links. |
| `analytics.html` | Board analytics snapshot with inline SVG visualisations. |

`workflows.html` and `improvements.html` were retired in plan 10. The
`Dab Improvements` category is still surfaced on the Notice Board;
deep-link directly to it via `index.html?category=Dab+Improvements`
(activates the category tab and shows a `clear` banner).

See `projects/printing-press-notice-cli.html` for the full #46 explainer.
