v0.1.0 - first tagged release
First tagged release. shmobster has been running in production under launchd for
a while; this puts a version on it.
A standalone Slack agent built bottom-up. Two requirements force it to exist:
multi-vendor API waterfall (rate limits) and multi-user Slack authz
(collaborators). Everything else is borrowed or transplanted, and credited.
What is in it
The loop - Slack Socket Mode to a tool-calling loop and back. Thread-as-session
context, configurable tool-step cap with a near-limit warning, and a final
tools-less answer when the cap is hit so the loop cannot dead-end. Mentions are
acked with a reaction so long tasks do not look silent, and duplicate mention
events are deduped.
Authz = f(user, channel) - per-channel policy covering working directory,
cloud profile and repo scope, held in a separate gitignored file with per-channel
credentials. Trusted users can reconfigure live via a set_policy tool behind a
trust gate. Policy re-resolves mid-turn, ~ expands, and a best-effort exclude
list marks paths off-limits under the working directory.
Mutating commands need approval - an approval flow with Slack-native
approve/deny buttons. A model-initiated policy change that gets refused posts a
refusal that does not blame the user.
Operational - a liveness watchdog that restarts when Socket Mode goes deaf,
service.sh reloading the plist rather than kickstarting it, identity derived
from configured label rather than a hardcoded name, and history labelled by real
speaker (self / sibling agent / human). Reads image and text attachments on a
mention.
Secrets - config takes ${VAR} interpolation so credentials are referenced by
name, never written as literals, and values are never logged (#73).
Credential hygiene, learned the hard way
That last item came out of a credential-leak audit run across our agent machines.
The transferable findings are written up as skills in
voitta-ai/skillz - agent-session-credential-audit
and agent-credential-leak-surfaces (latest catalog release: v1.9.0; an extension
covering the items below is open as PR #175). The short version, because it
changes how an agent should be built:
- Agent sessions are permanent plaintext records. A secret that appears in a
session for one second is on disk indefinitely, including the full stdout of
every command. Hence${VAR}references and never logging values. - A liveness probe lies in at least five distinct ways. Same status for valid
and invalid keys; a catalogue route that answers200to unauthenticated
callers; a live-but-spend-capped key answering400; non-2xx for both states;
and an endpoint that rejects an unrelated field before evaluating auth, so it
answers identically for every key. Always probe against a known-bad control, and
discriminate on the response body rather than the status line. - Fingerprint the exact byte span. Referring to secrets by a hash prefix is
right, but a pattern with a bounded quantifier records the hash of a truncated
span, and the entry can then never match the value it was meant to track - a
scrub reports clean while the secret is still there. - Verify a cleanup by fingerprint, never by pattern count. Documentation,
examples and test fixtures share the pattern permanently, so counting matches
makes a successful run look failed.
Open question for anyone building on this: should shmobster observe skills?
It does not today - there is no skill-loading mechanism in the codebase. The
skillz catalog currently targets claude and codex as hosts, and a third Slack-
native host is a plausible next step: same authored-once instructions, delivered
to the agent that is actually in the channel with you.
Open questions if we do it: which subset applies when the agent is multi-user
(skills are authored for a single operator), how per-channel authz interacts with
a skill that assumes a working directory, and whether skills load at startup or
resolve per turn like policy does. Opinions welcome on the issue tracker.
Credits
The workspace spine is transplanted from OpenClaw
(MIT), credited in #47. MIT licensed.