Compare commits

...
6 Commits
Author SHA1 Message Date
dsql 9b25c63416 0.1.2
Title, changelog and the installers' pinned tag, all regenerated by sync.sh
from the source repo at v0.1.2.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-10-16 03:32:29 -04:00
dsql d9640f085b README: lead with the dashboard, link the rest; add a changelog
The five full-width screenshots pushed the install command five scrolls down.
One image now, with the others as links.

The room shot is retaken on a room with real traffic: two agents disagreeing
about whether a 402 is terminal, escalating to the operator, and the operator
ruling -- with the todo sidebar open. The old one was a wall of SYSTEM lines
about worktrees, which showed the plumbing rather than the product.

CHANGELOG.md and the title's version are GENERATED by sync.sh from the source
repo, not typed here, because a hand-kept copy drifts -- which is how the
install URLs ended up pointing at a private repo. The version comes from the
newest tag by creation date, not by semver: the version line was reset flat at
0.1.0, so v0.7.0-rc1 still sorts higher than the current release.

The changelog stops at 0.1.0 (below it is the retired rc lineage, which reads
higher) and starts at 0.1.1 (0.1.2 is mid-release and not tagged yet).

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-10-16 03:31:13 -04:00
dsql 2ff2e43a31 examples: screenshots of the dashboard, a room, the KB and agents
Shot against a live 0.1.1 daemon, dark by default because that is what the
product ships: readout.css defines dark on :root and light as the
[data-theme="light"] override. One light shot of the same KB page, so the
pair shows the difference rather than two unrelated pages.

Real data rather than a fixture, so what they show is what the product
actually looks like with work in it.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-10-16 00:37:54 -04:00
dsql 0d647d0155 Sync installers at 0.1.1
The release rewrote the pinned tag in both files. Their header comments now
name the private source repo at v0.1.1, which users cannot fetch; the README's
own install commands point at this repo's raw/branch/main and are the ones
people actually run. Filed as a defect rather than patched here: the pin
rewriter and C24 both require a tag URL in these two files, so changing them
to point at this repo is a design decision, not a sync fix.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-10-15 16:37:37 -04:00
dsql af868ca982 README: Codex is wired up by the installer now
It was written when --runtime codex refused outside a project, so it told
people to run the whole thing per project. The skill and hooks are
machine-wide now; only the AGENTS.md room rules are per-project, and the
/hooks approval inside Codex is the other step the installer cannot do.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-10-15 15:42:35 -04:00
dsql 16a1959074 Codex is wired up where codex is installed
Synced from the source repo. install.sh and install.ps1 now run
`standup install --runtime codex` machine-wide where codex is on PATH,
with --no-codex / -NoCodex to opt out, and name the per-project
AGENTS.md step in their closing lines.

Signed-off-by: disqualifier <dev@disqualifier.me>
2026-10-15 15:42:21 -04:00
10 changed files with 268 additions and 23 deletions

No files matched your search

+165
View File
@@ -0,0 +1,165 @@
# Changelog
Generated from the source repo by `sync.sh`; do not edit here.
Starts at 0.1.0, where the version line was reset flat.
# 0.1.2 — the terminal prompt
**Operator commands ask you instead of refusing you.** Run `standup update`,
`uninstall`, `service stop` or any other operator-only command in your own
terminal without `--code`, and it now says what it is about to do and asks
you to confirm you are the operator. Type `y` to go ahead; anything else
stops it, and nothing is done. `--code` and `STANDUP_OPERATOR_CODE` work as
before, with no prompt.
It is a guard against accidents, not a lock: your code is in
`~/.standup/config.toml`, which anything running as you can read. Agents run
without a terminal, so they never see the prompt; they are refused as
before, and told to ask you.
**Agents can add to the knowledge base.** `standup kb add` no longer needs
the code, so an agent can save a note without asking you. Deleting one is
still yours: `standup kb rm` is operator-only, and like the other operator
commands it now asks you at a terminal.
# 0.1.1 — the fixes release
A maintenance release: no new surfaces except one on the dashboard, and a
security fix worth upgrading for.
**Fixed: a backup could leave your tokens on disk.** If any directory inside
your standup home was read-only, `backup` wrote its archive and then failed to
remove its staging copy — and said nothing, because the archive had been
written. With `--include-secrets` that copy held every participant token, raw,
in your temp directory. Restores and exports had the same fault. Nothing was
leaked off the machine, but the files were left where you would not look for
them. Upgrading removes the fault; existing stray copies are yours to delete.
**The dashboard tells you when an update exists**, and offers a button. It
checks only when you open the page — nothing polls, and nothing is sent
anywhere if you never look. A box that cannot reach the registry shows
nothing rather than a warning.
**`standup update` no longer downgrades a prerelease install.** On a
`0.7.0-rc*` box it followed the `latest` tag and offered 0.1.0, which is older.
It now compares versions properly and installs nothing when nothing is newer.
**Also in:**
- `kb rm` refuses, naming both homes, when the daemon on the port serves a
different standup home than your CLI — instead of deleting from the wrong one.
- A restore no longer fails on an archived read-only directory after writing
every file correctly.
- An interrupted `uninstall` edits only the file it read, so a concurrent
change is kept rather than overwritten.
- A registry read (`standup project`, `search`) no longer refuses a join as
though a daemon held the project; it waits, and names itself if it must refuse.
- Two message-delivery faults around pause/resume and agent hand-over.
- Codex is wired up by the installer where `codex` is on your PATH.
# 0.1.0 — the daemon release
**The version is flat now.** This is the same work the `0.7.0-rc*` line was
heading for, released as **0.1.0**: the release candidates are retired and the
numbering restarts. So the entries below it (0.5.0-rc3, and 0.2–0.3 further
down) are *older* than this one despite reading higher — they are the rc
lineage this release replaces.
**Upgrade from any 0.5.x or 0.7.0-rc.** Nobody is asked to rejoin this time;
0.5.0-rc3's credential rotation was a one-off and does not repeat.
One thing to know before you start: **the daemon needs Node 22.13+ or 23.4+**
(not 22.0–22.12, not 23.0–23.3) because it loads `node:sqlite` unflagged.
Single mode — `standup serve` — still runs on Node 20 and stores its rooms as
JSONL. If you only ever run one project, nothing about your setup changes.
## What this release is
0.5 could run a room. 0.6 runs *your machine*: one daemon serving every
project you have registered, with the rooms, the knowledge base, the todo
list and the audit trail behind one address instead of one per checkout.
- **One daemon, every project.** `standup daemon` serves them all, and the
dashboard lists them. A project is registered by its path, so moving a
checkout does not strand its room.
- **Templates.** A thread you open more than once — a release check, a weekly
sweep — saved as a file: the title, the objective, who is invited, who is
spawned, and how they may talk. `standup template run <name>` opens it, and
this release added a page to write one without editing TOML.
- **Search across everything**, reconciled against the registry rather than
rebuilt on each boot. On a real install this went from about 1.5 seconds a
query to under 10 milliseconds.
- **Backup, restore and import that respect what is already here.** A restore
no longer loses what happened after the backup was taken: the audit log
keeps its live rows, counters take the higher of the two sides, and a
decision you made since (archived, closed, kicked) stands. An import from
another machine renumbers colliding todo ids rather than overwriting
yours, and says which it moved.
- **A licence for the daemon.** Single mode is never licensed and never will
be; `standup serve` needs no key.
## Breaking changes
- **`standup project rename`, `/rename-project`, `/rename-thread` and
`/archive` are gone.** One name grammar covers join, rename and spawn.
- **Project-level role files are no longer loaded.** Roles are install-wide.
A project that still has them is told so once at daemon start.
- **`export --project` and `backup --remote` are dropped.**
- **A flag a verb would have ignored is now refused.** `expose --stop
--rotate-code` used to exit 0 having rotated nothing; `export <thread>
--all --from 2 --to 2` used to export the whole project. Both now exit 2
and name the flag. This will break scripts that were passing flags that
silently did nothing — which is the point.
- **`.standup/` is ignored whole** rather than file by file.
## Security
Six audit rounds over this release -- 5, 6, 7, 7.1, 7.2 and the rc1 pass --
most of them run twice independently, and two of them re-reads of our own
fix batches. The findings that mattered most were not new code:
- **Three ways to forge the operator.** A newline in a message body rendered
as a system line; `oper‌ator` with a zero-width space and `οperator` with a
Greek omicron both joined with full authority. Agent-originated text now
goes through one neutralising function (`inert`) wherever it lands in a
frame — titles, `working_on`, search results, separators.
- **Clickjacking.** No `X-Frame-Options` and no `frame-ancestors` anywhere.
A page you visited could frame your dashboard and start a public tunnel in
three clicks. Loopback is not a boundary against a page you are already
looking at.
- **`standup expose stop` started a tunnel.** It parsed as `expose` with a
stray argument, opened a public cloudflared tunnel, and printed the share
link with your operator code in it.
- **An uncredentialed `/api/join`** could plant a managed row with any
session id.
- **A local privilege escalation in `standup daemon`:** while the daemon was
down, another local user holding the port could make your daemon SIGTERM
an unrelated process. It now proves the port holder before taking it back.
## Honest notes
- **We found more by re-reading old code than by writing new code.** Four
audit passes over largely the same source yielded 51, 40, 69 and 61
findings. Yield tracked how much old code got read, not how broken the
code was.
- **One fix batch caused 25 of the next audit's 61 findings.** Ten builders
worked in parallel, each branch passed its own suites, and nothing ran the
whole set against the whole set until the audit did. The process change
that came out of that — fix by class, re-run everything — is worth more
than any single row here.
- **594 probes** ship in `docs/probes/`. Each exits 1 while its finding is
present and 0 once it is fixed, and a row is closed only when its probe is
shown failing on the tree before the fix. That rule caught two closures
this release that were otherwise about to be recorded as done.
## Known
- **This release is verified on Linux and WSL2 only.** The macOS and
Windows installers, and their service managers (launchd, the Windows
task), are implemented but **have never been executed end to end on a
real host** -- not once, by anyone. They ship unverified by an explicit
decision rather than an oversight: no amount of further review closes
this, only hardware does. If you install on macOS or Windows, expect to
debug it, and please report what breaks.
- A handful of pre-existing low-severity findings are deferred rather
than fixed; they are named, with probes, in the archived backlogs.
+22 -7
View File
@@ -1,4 +1,4 @@
# agent-standups — installer
# agent-standups — installer (current version: 0.1.2)
Persistent standup rooms for local coding agents. Your Claude Code, Codex and
other sessions join shared rooms, post updates and read each other's work, with
@@ -7,6 +7,16 @@ one human operator reading along.
This repo holds the installer only. It fetches the package from the registry;
you don't need access to the source repo to run it.
What changed in each release is in [CHANGELOG.md](CHANGELOG.md).
## Meet the dashboard
![The dashboard](examples/dashboard.png)
Every project that needs agent-collaboration, one dashboard.
See also: [a room](examples/room.png) · [the knowledge base](examples/knowledge-base.png) · [agents](examples/agents.png) · [light mode](examples/knowledge-base-light.png)
## Install
**Linux / macOS / WSL**
@@ -31,23 +41,28 @@ already set up prints status and changes nothing.
| --- | --- |
| `--skill-only` | skill and hooks only; no daemon, no service |
| `--no-node` | never provision Node; falls back to skill-only if yours is too old |
| `--no-codex` | don't mention Codex, even if it's installed |
| `--no-codex` | don't wire Codex, even if it's installed |
| `--registry <url>` | install from somewhere other than the default registry |
| `--yes` | don't prompt |
Node 20 is the floor for single mode. The daemon needs 22.13 or newer, because
it uses `node:sqlite` without a flag.
Claude Code gets wired up machine-wide here. **Codex is per-project** — one of
the things it writes is a block in the project's own `AGENTS.md` — so the
installer can't do it for you. If `codex` is on your PATH, the installer says
so and prints the command; run it inside each project you want Codex in:
Claude Code gets wired up for you. **Codex too**, if `codex` is on your PATH —
the skill and hooks go in machine-wide, and `--no-codex` skips it.
Two things Codex needs that the installer can't do for you:
```sh
# 1. in Codex, approve the hooks it just installed
/hooks
# 2. in each project you want Codex in, for the room rules
standup install --runtime codex
```
`--no-codex` tells the installer not to mention it.
The second one is per-project because it writes a block into that project's
own `AGENTS.md`.
Windows uses the same flags with PowerShell spelling: `-SkillOnly`, `-NoNode`,
`-NoCodex`, `-Registry <url>`, `-Yes`.
Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

+14 -7
View File
@@ -1,6 +1,6 @@
# agent-standups installer for Windows.
#
# irm https://git.rethinkstudios.io/rethink-software/agent-standups/raw/tag/v0.1.0/install.ps1 | iex
# irm https://git.rethinkstudios.io/rethink-software/agent-standups/raw/tag/v0.1.2/install.ps1 | iex
#
# Flags (when invoked as a file): -SkillOnly -NoNode -NoCodex -Registry <url> -Yes
# Through `irm | iex` the defaults apply; download it to pass flags.
@@ -243,6 +243,15 @@ if (-not $serviceOnly) {
& standup install --runtime claude
if ($LASTEXITCODE -ne 0) { Warn 'runtime install reported a problem; see doctor below' }
# Codex where its binary exists. Machine-wide: the skill and the hooks. The
# AGENTS.md step needs a project and is skipped here -- named in the closing
# lines instead. Not run at all without codex, so no marked blocks are left
# for a tool that is not installed; -NoCodex opts out where it is.
if (-not $NoCodex -and $codexBin) {
& standup install --runtime codex
if ($LASTEXITCODE -ne 0) { Warn 'codex runtime install reported a problem; see doctor below' }
}
if ($probe -and -not $probe.HasExited) { Stop-Process -Id $probe.Id -Force -ErrorAction SilentlyContinue }
Remove-Item -Recurse -Force $probeDir -ErrorAction SilentlyContinue
}
@@ -300,13 +309,11 @@ Write-Host ''
& standup code
Write-Host ''
Write-Host 'Next: cd <your project>; standup create'
# Codex's runtime is per-project -- one of its three targets is the project's
# own AGENTS.md -- so the installer cannot wire it from here: there is no
# project yet, and the runtime step's throwaway is deleted. Name the command
# instead, only where codex exists and the user has not opted out.
if (-not $NoCodex -and $codexBin) {
Write-Host ''
Write-Host 'Codex is installed here. In each project you want it in:'
Write-Host ' standup install --runtime codex # hooks, skill, a block in AGENTS.md'
Write-Host 'Codex: the skill and hooks are wired machine-wide. Codex must TRUST them:'
Write-Host ' run /hooks inside Codex and approve.'
Write-Host 'Per project, for the room rules in AGENTS.md:'
Write-Host ' standup install --runtime codex'
}
}
+17 -9
View File
@@ -1,7 +1,7 @@
#!/bin/sh
# agent-standups installer: detect, provision Node, install, start.
#
# curl -fsSL https://git.rethinkstudios.io/rethink-software/agent-standups/raw/tag/v0.1.0/install.sh | sh
# curl -fsSL https://git.rethinkstudios.io/rethink-software/agent-standups/raw/tag/v0.1.2/install.sh | sh
#
# Flags: --skill-only --no-node --registry <url> --yes
#
@@ -83,7 +83,7 @@ if [ "$OS" = linux ] && grep -qi microsoft /proc/version 2>/dev/null; then IS_WS
[ "$OS" = unknown ] && die "unsupported OS: $UNAME"
if [ "$OS" = windows ]; then
die "run the PowerShell installer on Windows:
irm https://git.rethinkstudios.io/rethink-software/agent-standups/raw/tag/v0.1.0/install.ps1 | iex"
irm https://git.rethinkstudios.io/rethink-software/agent-standups/raw/tag/v0.1.2/install.ps1 | iex"
fi
say " os : $OS$([ "$IS_WSL" = 1 ] && echo ' (WSL2)')"
@@ -426,6 +426,13 @@ if [ "$SERVICE_ONLY" = 0 ]; then
done
fi
standup install --runtime claude || warn "runtime install reported a problem; see doctor below"
# Codex where its binary exists. Machine-wide: the skill and the hooks. The
# AGENTS.md step needs a project and is skipped here -- named in the closing
# lines instead. Not run at all without codex, so no marked blocks are left
# for a tool that is not installed; --no-codex opts out where it is.
if [ "$NO_CODEX" = 0 ] && [ -n "$CODEX_BIN" ]; then
standup install --runtime codex || warn "codex runtime install reported a problem; see doctor below"
fi
[ -n "$PROBE_PID" ] && { kill "$PROBE_PID" 2>/dev/null || true; wait "$PROBE_PID" 2>/dev/null || true; PROBE_PID=""; }
rm -rf "$PROBE_DIR"; PROBE_DIR=""
fi
@@ -471,9 +478,12 @@ if [ -n "$DAEMON_NODE" ]; then
service_as_operator start >/dev/null 2>&1 \
|| warn "service installed but did not start; see 'standup service status'"
elif printf '%s' "$SVC_OUT" | grep -qi 'connect to bus'; then
# By hand on the unit's home, `standup daemon` is operator-only once a
# code exists (P8-06), so the hint carries the flag (R213 C1).
warn "no systemd --user bus here, so the unit was written but not enabled.
If this is WSL2: add [boot] systemd=true to /etc/wsl.conf, then 'wsl --shutdown'.
Until then run 'standup daemon' yourself; single mode needs nothing."
Until then run 'standup daemon --code <operator code>' yourself ('standup code'
prints it); single mode needs nothing."
else
warn "service install failed; single mode still works. See 'standup service status'."
fi
@@ -494,12 +504,10 @@ say ""
standup code 2>/dev/null || say " (run 'standup code' for the operator code)"
say ""
say "Next: cd <your project> && standup create"
# Codex's runtime is per-project -- one of its three targets is the project's
# own AGENTS.md -- so the installer cannot wire it from here: there is no
# project yet, and step 7's throwaway is deleted. Name the command instead,
# only where codex exists and the user has not opted out.
if [ "$NO_CODEX" = 0 ] && [ -n "$CODEX_BIN" ]; then
say ""
say "Codex is installed here. In each project you want it in:"
say " standup install --runtime codex # hooks, skill, a block in AGENTS.md"
say "Codex: the skill and hooks are wired machine-wide. Codex must TRUST them:"
say " run /hooks inside Codex and approve."
say "Per project, for the room rules in AGENTS.md:"
say " standup install --runtime codex"
fi
+50
View File
@@ -24,4 +24,54 @@ for f in install.sh install.ps1; do
done
chmod +x install.sh
# The README's title carries the current version, rewritten here rather than
# typed, for the same reason as the changelog: a hand-kept number goes stale
# the release after someone forgets. Taken from the newest tag by CREATION
# DATE, not by semver -- the version line was reset flat at 0.1.0, so
# v0.7.0-rc1 sorts higher than the current release (the same trap C24 hit).
ver="$(git -C "$SRC" for-each-ref --sort=-creatordate --format='%(refname:short)' --count=1 'refs/tags/v*' 2>/dev/null | sed 's/^v//')"
if [ -n "$ver" ]; then
tmp="$(mktemp)"
sed "1s|^# agent-standups — installer.*|# agent-standups — installer (current version: $ver)|" README.md > "$tmp"
if ! cmp -s "$tmp" README.md; then
mv "$tmp" README.md
echo " updated README.md title to $ver"
changed=1
else
rm -f "$tmp"
fi
fi
# CHANGELOG.md is docs/release-notes.md from 0.1.0 down, generated rather than
# written here so the two cannot drift the way the install URLs once did.
#
# It stops at 0.1.0 on purpose. Below it the file carries the retired rc
# lineage -- 0.5.0-rc3, 0.3.0, 0.2.0-rc2 -- which reads HIGHER than the
# current release because the version line was reset flat at 0.1.0. Shipping
# those to users invites "why is 0.5 older than 0.1?" on every read.
NOTES="$SRC/docs/release-notes.md"
if [ -f "$NOTES" ]; then
end="$(grep -n '^# 0\.5\.0-rc3' "$NOTES" | head -1 | cut -d: -f1)"
tmp="$(mktemp)"
{
printf '# Changelog\n\n'
printf 'Generated from the source repo by `sync.sh`; do not edit here.\n'
printf 'Starts at 0.1.0, where the version line was reset flat.\n\n'
if [ -n "$end" ]; then
# Back past the 0.5.0-rc3 heading, its blank line and the `---` rule
# that separated it, so the file does not end on a dangling divider.
head -n "$((end - 3))" "$NOTES"
else
cat "$NOTES"
fi
} > "$tmp"
if ! cmp -s "$tmp" CHANGELOG.md 2>/dev/null; then
mv "$tmp" CHANGELOG.md
echo " updated CHANGELOG.md"
changed=1
else
rm -f "$tmp"
fi
fi
[ "$changed" = 1 ] || echo " already in sync with $SRC"