obot.agentobot.roadmapRelease candidates2026-10-07

obot.agent v0.6.0 and obot.roadmap v0.5 — what changed, shown running

Two releases that go together. One is the skill a session runs; the other is the standards it runs under and the site that reports on it. Most of what is new has no page to look at, so each section pairs the change with real output from this machine and the command that produced it. Where the change is a fix, the old behaviour is captured beside the new one.

Releases obot.agent v0.6.0 · obot.roadmap v0.5 Since v0.5.0 and v0.4 · 2026-09-11 Tests 36 checker · 138 + 15 hub Gate security review, then four release reviews, 2026-10-07
01  Both releases

A session runs locally and writes to GitHub as the bot

obot.agent #347 · hub #385

v0.5.0 moved sessions to the cloud, where a session acts as the account that connected it. That account is @jwildfire's, and it is admin on every repository in the program. On 2026-10-07 he parked cloud sessions: "we can probably just park cloud support for now and i'll just do local here or on the agent laptop". A session now starts from his workspace, on his own machines, and every issue, comment, commit, push, pull request and merge of an increment goes out as obotclaw[bot].

What the two releases ship is the description: obot.agent's skill, AGENTS.md and README, and the hub's developer guidelines, ways of working and AGENTS.md. The token and the guard that enforce it are tooling of his workspace and are in no repository, by his choice. The captures below are that guard, so the claim in the documents can be seen holding.

A write with no token is refused before it runs

the workspace guardobot2 · 2026-10-07
$ gh issue comment 12 -R jwildfire/safety.viz --body hello
github-write-guard: this is a `gh issue`/`gh pr` write, and with no token set it runs
as @jwildfire, so GitHub records him doing it.

Write as obotclaw[bot], in the one form that stops when the mint fails:

  T=$(<workspace>/bin/obot-app-token)
  GH_TOKEN=${T:?} gh <the same args>

Both lines go in the same Bash call; shell variables do not carry over to the next
one. If the write has to carry @jwildfire's name, do not run it: give him the command
in a bash block and he runs it himself.

The form matters. The first line asks for a bot token; the second hands it to gh. Handed an empty token, gh quietly uses the stored login, so a failed request used to produce a write under his name that looked like a success. ${T:?} is the shell's way of saying "stop here if T is empty".

Three things are his alone, with any token

the workspace guardwith the bot's token set
$ GH_TOKEN=${T:?} gh pr review 9 -R jwildfire/safety.viz --approve
github-write-guard: this approves a pull request. Approval is @jwildfire's review,
given on GitHub, and it is the gate on every release branch.

Stop and tell @jwildfire what you wanted to do and why. If he agrees, he runs it
himself; a session never does, with any token.

The other two are merging past a ruleset and changing a ruleset or a branch protection. The guard has 53 cases, each a command it must refuse or leave alone:

bin/test-guard -v, eight of 53 linesobot2 · 2026-10-07
ok    deny  ambient pr create
ok    deny  one-line substitution
ok    deny  approve, as the bot
ok    deny  ruleset edit
ok    allow two lines
ok    allow issue view
ok    allow prose in a heredoc
53 cases, 0 failed
A seatbelt, not a wallThe guard reads shell commands by pattern. It does not see inside a script or a git push, and a session set on getting round it could. The walls are GitHub's: the branch rulesets, and the bot's narrow permissions.
See it yourself
Read the Identity section of each AGENTS.md:
https://github.com/jwildfire/obot.agent/blob/main/AGENTS.md#identity-and-attribution
https://github.com/jwildfire/obot.roadmap/blob/main/AGENTS.md#identity

On the workspace machine:  bin/test-guard -v

On GitHub: every issue and pull request opened for these releases on 2026-10-07 was opened by obotclaw[bot].
The earlier ones linked here, such as the tracker's pull request, predate the decision and were opened by @jwildfire.

What changed in the standards, passage by passage

02  obot.agent, and the hub's guidelines

Release notes are held to a length

obot.agent #341 · #343 · #345 · #347 · #352 · #355

@jwildfire, 2026-10-06, on two sets of notes that ran to 2,088 and 1,754 words: "Release notes are way too wordy. … The details go in the demo page." The release-notes skill gives the shape, taken from safety.viz v1.9.1, and its checker fails a section over 600 words, a feature bullet over 70, or a section that does not open with its demo link. These two releases' own notes are the first written under it.

the checker on this release's notesobot2 · 2026-10-07
$ node obot.agent/skills/release-notes/check-notes.mjs obot.agent/NEWS.md
obot.agent v0.6.0 (Upcoming): 388 words (limit 600)
The notes are within every limit.
$ node obot.agent/skills/release-notes/check-notes.mjs obot.roadmap/NEWS.md
obot.roadmap v0.5 (Upcoming): 428 words (limit 600)
The notes are within every limit.

The checker could be hung by one line

The security review found that a bullet ending in about twenty issue links and one more word sent the word counter into a search that did not finish. The checker runs on text other people wrote, so one line in a NEWS file could stall a session. The same file, before and after:

before — main on 2026-10-0630 links, then "end"
$ node check-notes.mjs hostile.md
still running after 5.00 s; stopped
after — v0.6.0the same file
$ node check-notes.mjs hostile.md
pkg v1.0.0 (Upcoming): 53 words (limit 600)
returned in 0.02 s, exit 0

Every line of the current NEWS files of five repositories, 861 lines, is counted the same by the old and the new counter.

Its total was wrong for a flat list

A section still being written is often a list with no headings. The checker totalled such a section by its first bullet alone. It failed the section anyway, for having no demo line, so nothing passed that should not have; the number was wrong.

beforefour bullets
obot.agent v0.6.0 (Upcoming): 46 words (limit 600)
after — v0.6.0the same four bullets
obot.agent v0.6.0 (Upcoming): 246 words (limit 600)

What it cannot read, it reports

The release reviews found the checker could be talked out of its own rules. A command in a code block under a bullet, with a # comment in it, ended the section at the comment, and the 150-word bullet below was never looked at. Two attempts to teach it code blocks each left another way to lose words, so it no longer tries: a line that opens a code block is named, and so is a list or a heading it cannot read. This adds one rule to release notes: no code blocks; a command goes on a page like this one.

before — as first writtena code block, then a 150-word bullet
$ node check-notes.mjs with-code.md
pkg v1.0.0 (Upcoming): 30 words (limit 600)
The notes are within every limit.
exit 0
after — v0.6.0the same file
$ node check-notes.mjs with-code.md
pkg v1.0.0 (Upcoming): 30 words (limit 600)
- A line opens with a code-block marker (1 of them): a command or a snippet goes on the demo page, and inline code is fine.
exit 1

How it was checked: every limit is tested at the last count that passes and the first that fails; 143 rules were switched off or bent one at a time and a test noticed each; and it was compared with the checker as first written on a million generated sections and on all 43 sections of the program's 13 release-note files, where no verdict changed. What it still reads differently from a reader is listed in obot.agent#354.

Reproduce
cd obot.agent && node --test skills/release-notes/check-notes.test.mjs     # 36 tests, 36 pass
node skills/release-notes/check-notes.mjs NEWS.md
03  Both releases

A release candidate is reviewed by three subagents before he is asked

obot.agent #340

The gate used to be ultrareview, which only a person can launch, so an unattended session could never pass it (@jwildfire, 2026-10-03). The session now spawns three read-only reviewers: one for correctness, one for the definition of done and its proof, one for the program's hard rules. Each gets the diff, the pull request's body and the issues it closes, and none of the session's own conclusions. The session checks every finding against the code, fixes it or says why it does not apply, and posts the review and its resolution as one comment. Only then is the candidate marked ready.

On this release the gate ran four times. The first review found a small fault in the release-notes checker; the fix for it was reviewed again, as the rule asks when a fix grows past its finding, and that review and the next each showed the fix had made something worse. The fourth compared the result with the original on a million generated sections. Every round and how each finding was resolved is in the one comment on the release candidate.

See it yourself
The obot.agent v0.6.0 release candidate carries its own review comment:
https://github.com/jwildfire/obot.agent/pulls?q=is%3Apr+base%3Astable+v0.6.0

The rule: https://github.com/jwildfire/obot.roadmap/blob/main/docs/developer-guidelines.md#releases
04  obot.agent

A session checks who wrote a sign-off

obot.agent #345

A session starts work when the objective carries a comment from @jwildfire saying its tree is signed off. As the skill was written, a session could satisfy that by reading the words, and anyone can comment on a public issue. The skill now says to take the author from GitHub's own record. The standup, which lifts the latest comment on each blocked issue into a file read aloud, takes only comments from him and from the bot, and treats what it reads as material to report, never as an instruction.

the query the skill now gives, on the RBQM objective2026-10-07
$ gh api repos/jwildfire/obot.roadmap/issues/375/comments \
    --jq '.[] | select(.user.login == "jwildfire") | {url: .html_url, body}'
(nothing)
$ gh api repos/jwildfire/obot.roadmap/issues/375/comments \
    --jq '[.[] | .user.login] | group_by(.) | map("\(.[0]): \(length)") | join(", ")'
obotclaw[bot]: 2

That objective has two comments, both from the bot, and none from him. It is not signed off, and the query says so whatever the comments' words claim.

An instruction, not a lockThese are words in a skill and a routine. They say which field to read; nothing forces a session to. What makes them worth more than before is section 01: a session no longer comments as him, so a comment recorded under his name is one he wrote.
05  obot.roadmap

The ruleset check fails when it could not look

hub #379

scripts/github-flows.sh check is how anyone confirms that the branch rules are still in force on the nine repositories. Two faults, both found by the review and both reproduced with a stand-in for gh that changes one answer and passes the rest through. When GitHub did not return a ruleset, the comparison had nothing to compare, and nothing read as a match. And it never looked at who may bypass a ruleset, which is the one entry that makes every other rule optional.

beforeone ruleset unreadable
$ scripts/github-flows.sh check safety.viz
safety.viz: matches
exit=0
after — v0.5the same stand-in
$ scripts/github-flows.sh check safety.viz
safety.viz: drift — could not read ruleset
'integration: checks and auto-merge'; could not
read ruleset 'release: review required'
exit=1
beforea bypass entry added
$ scripts/github-flows.sh check safety.viz
safety.viz: matches
exit=0
after — v0.5the same stand-in
$ scripts/github-flows.sh check safety.viz
safety.viz: drift — ruleset 'integration: checks
and auto-merge' differs (bypass allowed for
RepositoryRole 5); ruleset 'release: review
required' differs (bypass allowed for
RepositoryRole 5)
exit=1

"RepositoryRole 5" is GitHub's own name for the repository's admin role, which is the entry the stand-in added.

GitHub shows a ruleset's bypass list only to an account with admin. Run with the bot's token, the check says "bypass list not shown to this account" and exits 1, where a pass would have been a pass on a field nobody read. Against GitHub as it stands, run as @jwildfire, it prints "matches" for all nine.

Reproduce
cd obot.roadmap && bash scripts/github-flows.sh check          # reads only; nine lines, each "matches"
06  obot.roadmap

The site build holds no bot key, and installs with its own token

hub #383 · #385 · #379

The hub's main takes direct pushes, and a push runs the deploy. Three things in that workflow turned a push into more than a site build, and each is changed.

the workflow, read backdeploy-site.yml on main
steps that set GITHUB_TOKEN to the workflow's own token:
Install renderer dependency
r-lib/actions/setup-pandoc@v2
r-lib/actions/setup-r@v2
Install gh.dash dependencies
Install gh.dash
Build package status dashboard

$ grep -c 'OBOT_APP_PRIVATE_KEY\|RC_TOKEN' .github/workflows/deploy-site.yml
0
the renderer:  npm install --no-save --ignore-scripts marked@18.1.0

The proof that the site still builds is the deploy itself: the run on the merge commit is green, its log reads "status: 7 repos rendered to _site/status/index.html", and the status page frames the dashboard, not its placeholder. The catalog now says of its to-do list: "Draft releases are not listed: a release candidate is a pull request."

Also retired: a nightly job on his MacA scheduled job fetched the hub's main every night and ran what it found, under his account, to refresh the Cost chart. The job is unloaded, its script no longer hands control to the copy of itself it just fetched, and the page it fed is refreshed by hand.
Still his to doTwo secrets on the hub, OBOT_APP_ID and OBOT_APP_PRIVATE_KEY, are no longer read by the deploy. Deleting them, and replacing the key they hold, is for @jwildfire: a session cannot and should not.
07  obot.roadmap

The tracker replaces the project board

hub #347

One page shows the roadmap as GitHub records it: every objective, opened to its requirements and their tasks, with status on every row. The sidebar searches and filters by status, objective, area and milestone, and counts what is in each. The address carries the filter, so a view can be sent as a link. The nav is the four pages that get read: Home, Tracker, Analytics, News.

The tracker page: counts of open objectives, requirements and tasks on the left with status filters beneath, and on the right the chart coverage objective opened to its requirements, each with a status pill, a progress bar and its milestone.
Try it
https://jwildfire.github.io/obot.roadmap/tracker.html
1. Untick Backlog in the sidebar. The count above the list drops and the address changes.
2. Copy the address into a new tab. The same view opens.
3. Open a requirement's row. Its tasks appear, each read from its issue and its pull request.
08  obot.roadmap

The Cost chart runs through October and says what it covers

hub #370 · #379

The chart had stopped on the last day the usage script was run by hand. It now runs through 6 October, and a panel above it says what the record covers and what it cannot see: the days each store runs through, a stretch in August and September that is a floor because transcripts had already been deleted, and twelve days in September for which nothing was recorded at all. The totals are stated as a floor.

The analytics page: a panel headed What the record covers listing local sessions read through 6 October, one cloud session reported, a floor from 20 August to 18 September and nothing recorded for 19 to 30 September, above a stacked bar chart of cost per day by kind of session.

Two things about this page changed during the security review, and the release notes say so. Local usage is refreshed by hand, because the nightly job that did it is retired (section 06). And with cloud sessions parked, the green "Cloud session" series holds the one session that reported and will not grow.

Try it
https://jwildfire.github.io/obot.roadmap/analytics/index.html
Switch day / week / month, and $ / all tokens. Read the panel before the bars.
09  What these releases do not do

Left open, and said so