Skip to content

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 20 Aug 18:06
dbd0d57

An operations release. The agent now tells you what it is running, refuses to
repeat a credential back to you, and has a fallback chain that does not fail all
at once.

Credential redaction (#72)

Everything the agent says is scrubbed before it leaves the process. run_shell
returns command output verbatim to a channel, and cat, env and printenv are
read-only -- they clear the YOLT gate and run with no approval. This was not
theoretical: a live config was found holding literal keys, where a single cat
would have posted all five to Slack.

Detection reuses voitta-yolt's secret_redact rather than a second pattern list
that drifts from it, so there is one source of truth. On top of it, the thing
YOLT cannot know: this process's own secrets -- Slack tokens, every waterfall
api_key, every per-channel policy env value -- matched by exact value, so a
credential in an unanticipated format is still caught when it is one of ours.

Scrubbing happens at collection, so the model's own context never holds a
credential to repeat later. The reply, the approval cards (which render a parked
command twice), the exception replies and the log formatter are all covered. The
formatter matters more than it looks: a logging.Filter sees only record.msg,
while the traceback from logger.exception is appended by the formatter from
exc_info -- which is exactly where a leaked credential would sit.

It fails loudly, never open: with the redactor unavailable the agent refuses to
start, and it is installed at import before any statement that can log.

Deliberately excluded: a generic "40 characters of base64" rule. It matches a git
SHA, and a redactor that mangles git log gets switched off.

Upgrade announcements (#77)

An instance announces itself in its channels the first time it boots on a version
it has not announced before, linking the release notes. The trigger is a version
change, not a boot -- the watchdog and launchd restart the process routinely, and
none of that is worth a message.

An instance with no recorded version announces too, without claiming an origin it
never had. Staying quiet there would have skipped the first rollout of this
feature, which is the one it was written for.

announce knows nothing about Slack; it takes a post(text) callable, and a
repo-scoped CLAUDE.md now carries the rule for the ingest modes that come
later.

A waterfall that does not fail all at once (#83)

Debugging an outage found all three configured vendors down simultaneously:
Anthropic capped (400), OpenRouter out of credits (402), NVIDIA on a retired
model id (404). A waterfall whose slots fail together is one outage listed three
times.

The example config now ships four independent failure domains --
anthropic -> gemini -> requesty -> openrouter -- with the lower rungs on free
tiers that are rate-limited separately from each other. Observed directly:
google/gemma-4-31b-it returns 429 on OpenRouter's free tier while the same
model answers through Requesty.

The README documents how to find free, tool-capable models on each router, and
the two rules that matter when adding one:

  • It must actually do tool calls. This is a tool-calling loop. A model that
    ignores tool schemas does not error -- it answers in prose and the agent looks
    lobotomized rather than broken. Declared support is not enough.
  • Pass a timeout. A free endpoint that hangs blocks the whole turn while the
    Slack ack spins.

Two traps are recorded there as well: NVIDIA's /v1/models answers 200 to any
bearer token, so it cannot tell you whether a key is valid; and model ids retire
without notice -- gemini-2.0-flash and meta/llama-3.1-405b-instruct both went
404 during this round of testing.

Known issue

A vendor that is out of budget is re-probed on every turn (#80). LiteLLM decides
cooldowns by HTTP status and cools only 429/401/408/404, so Anthropic's 400
usage-limit and OpenRouter's 402 insufficient-credits never park the deployment.
Fallback still works, so requests are answered -- the primary is just retried
each time before falling through. Filed upstream as BerriAI/litellm#37592.

Upgrading

git pull
.venv/bin/pip install -r requirements.txt
.venv/bin/python selfcheck.py            # prints the build it just checked
deploy/service.sh restart
  • voitta-yolt must be v1.0.0 or newer. Redaction imports secret_redact
    from the same tree as the exec classifier, and the agent will not start
    without it. git pull in your voitta-yolt checkout if it is behind.
  • New state file: shmobster-state.json (gitignored, path from
    SHMOBSTER_STATE) holds the last announced version. Nothing to create -- it
    is written on first boot.
  • Expect one announcement in each configured channel on the first boot after
    this upgrade.
  • No config changes required. The new example waterfall is a suggestion; an
    existing shmobster-config.json keeps working. Adopting it needs
    GEMINI_API_KEY and REQUESTY_API_KEY in the launchd environment, not only
    in ~/.bash_profile.