Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add instructions/ideaplaces/agent-inbox/claude-mdgit clone --depth 1 https://github.com/Ideaplaces/agent-inboxWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/instructions/ideaplaces/agent-inbox/claude-md)<a href="https://agentmods.dev/instructions/ideaplaces/agent-inbox/claude-md"><img src="https://agentmods.dev/badge/instructions/ideaplaces/agent-inbox/claude-md.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.03086 | $0.03086 |
| Opus 5 | $0.01543 | $0.01543 |
| Sonnet 5 | $0.00617 | $0.00617 |
| Haiku 4.5 | $0.00309 | $0.00309 |
Grade A, and why
agent-inbox CLAUDE.md scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured today.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 206 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Agent Inbox: working notes
The Mac app is in mac/, the senders are bash at the repo root. mac/README.md
has the architecture and the design decisions; this file is what someone
changing the code needs to know.
Release credentials, the signing certificate and the machine that builds the DMG are deliberately not here. They are IdeaPlaces-internal and this repository is public.
Local development
cd mac
swift test # no network, no side effects
./build.sh --debug # ad-hoc signed, host architecture, fine for running yourself
SIGN_IDENTITY="Developer ID Application: ..." ./build.sh
Copying a local build over /Applications replaces the released one, so brew's
recorded version will disagree with what is installed until the next upgrade.
Harmless, but it explains the mismatch.
The senders are testable without a transport:
./test-notify.sh # runs notify.sh against a throwaway HOME, prints instead of posting
Gotchas already paid for
Each of these shipped a release that looked healthy and was not. The full write-up, including the fixes, is at docs.ideaplaces.com/devops/macos-app-signing.
- The build number has to rise. Sparkle compares
CFBundleVersion, not the marketing version. It came fromgit rev-list --count HEAD, which is1on CI because checkout clones to depth 1, so every release shipped build 1 and no update was ever offered. Now derived from the version. --timestamp=nonefails notarization. Ad-hoc signing requires it and Apple rejects it, so branch on the identity.- Staple the app, not only the DMG. A ticket on the image does not travel with
the app into
/Applications, leaving a Mac that is offline at first launch with nothing to fall back on. --deepis wrong once a framework is embedded. Sign inner-out: Sparkle's XPC services,Updater.app,Autoupdate, the framework, then the app.- Library validation needs matching Team IDs. An ad-hoc signature has none, so a local build dies loading Sparkle. Ad-hoc builds use a separate entitlements file that relaxes it; never ship that file.
hdiutil create -srcfolderneeds a writable mount. Managed Macs and CI runners force disk images read-only. Usemakehybrid.- Apple's timestamp server fails under load.
A timestamp was expected but was not found.broke the v0.1.5 release on a Sparkle XPC service. The timestamp is mandatory for notarization, so signing retries with backoff rather than failing the release. - Build against the SDK the app will run on. 0.1.8 was built on the hosted
macos-14image, so it links against the macOS 14.5 SDK. On macOS 26 that binary grows itsMenuBarExtrawindow and never shrinks it again: the window stays at the tallest list of the session (measured at 560x472) while the content draws its real height, and SwiftUI centres the content in the leftover space. The result is a menu floating ~140pt below the menubar with dead margin above and below, which reads as a padding bug and is not one. The same source built with the macOS 26 SDK goes 652 -> 157 across the same shrink. Check withvtool -arch arm64 -show-build <binary> | grep sdkbefore chasing a layout problem that only appears on one Mac. - A Focus profile silences notifications and nothing in the API says so.
UNUserNotificationCenterreportedauthorized,alert: enabled,sound: enabled; audio output was fine; and"Pop","Pop.aiff"and.defaultwere all silent. A Focus mode the app cannot see was filtering it. Before chasing a sound name or a permission, ask whether Focus is on: the app has no way to detect it andadd()reports success either way. - The hook runs
~/.agent-inbox/bin/notify.sh, not your checkout. The app unpacks it from the bundle at launch, so a fix in the repo does nothing until a build carrying it is installed. A local build made before the fix will happily overwrite the good copy. Check withgrepagainst the installed file, not the one you edited. - A file left by a transport you stopped using keeps sending.
notify.shposts to whatever it finds in~/.agent-inbox/, so switching the app from Discord to ntfy left every session publishing to both for days with nothing to show it. The writer now retires the other transport's files. - The DMG window comes from a committed
.DS_Store. Without one, Finder opens the image at whatever size and icon scale it last used, which is the cramped default window. The usual way to make one is to mount the image read-write and drive Finder over AppleScript, and this project cannot: that is the same read-only-mount problem that madecreate -srcfolderunusable.mac/dmg/make-ds-store.pywrites the file directly, with no mount and no GUI, andmakehybriddoes carry dotfiles into the image. Re-run it only when the layout changes, and note that the names in it must match the staged files exactly or Finder silently falls back to automatic positions. - Finder drops a view-options dictionary it does not recognise, whole. The
0.1.24 image asked for 128pt icons and got Finder's default 64: the window
settings in
bwspapplied while every setting inicvpwas discarded, with no error and nothing in a log. The file carried two keys Finder never writes (scrollPositionX/scrollPositionY, plus a strayICVO) and was missing three it always writes (backgroundColorRed/Green/Blue). Match the key set of a.DS_StoreFinder itself produced, which means pulling one out of a shipping DMG and diffing against it. - The background picture needs the
pBBkbookmark, not only the alias.backgroundImageAliasinsideicvpis the older half and Finder does not resolve it on its own. Both are written now. - AppleScript cannot tell you whether the background applied.
background picture of icon view optionsreportsNONEfor images that certainly have one, checked against a third-party DMG as a control before trusting the reading.icon sizeand the window bounds do read back correctly, so verify what can be verified and have a person look at the rest. - The wire has a contract now, and two ways a message can reach the parser.
notify.shappends a versioned JSON line after the human lines and the old footer.Transport.splitFooterpeels the last body line only if it looks like a footer, so normally the JSON stays in the body and the footer arrives inside it; but if any contract string contains· /,splitFooterpeels the JSON intomessage.footerinstead.MessageParserchecks both places. Anyone rewritingsplitFooterneeds to keep both arrangements working, andMessageParser.peelFooterduplicates its two conditions on purpose so the model layer does not import the transport: change one, change both. - A contract with a null or unknown
kindfalls back whole. Half-applying a contract is worse than ignoring it, so the parser drops to the emoji heuristics for the entire message rather than filling what it can. closing_wordsnever contains a newline. Line ends are sentence ends by design. A test asserting a newline survives through.closingwill fail on the reduction, not on jq.HOST_LABELin the environment is ignored.notify.shassignshostname -sunconditionally before sourcing config, so only~/.agent-inbox/configcan set it.HOST_LABEL=x ./notify.shdoes nothing.- The dry-run output has no
footer:line any more. The footer is the second-to-last body line and the JSON contract the last.tail -1of a dry run is the contract. - Backoff after a failure starts at 2s, not 1s.
consecutiveFailuresis incremented before the sleep, so the ladder after failures is 2, 4, 8, 16, 32, 60.backoff(0), one second, is the wait after a healthy stream closes. Pinned inReceiverTests; change the loop and the test together. - The receiver's watchdog ends the connection; it used to only flag it. The
first streaming build set a flag at ten seconds but stayed inside the
for try awaituntil URLSession's 120s idle timeout threw, so the poll fallback began after two minutes, not ten seconds. Nothing caught it because nothing could: the loop calledTask.sleepdirectly. Making time injectable (Sleeper) is what surfaced it. Stream and watchdog are now siblings in a task group and the first to finish decides. receiver.restart()no longer restarts housekeeping. Reconnect and topic changes cycle the connection only; presence and expiry keep their own clock.- In receiver tests, settle on the last effect in the chain, not the first.
settle(until:)returns when its condition holds; state set one hop later may not be there yet. And two sleeps woken by oneadvanceresume in deadline order, but the main actor does not promise to run them in that order, so never assert cross-task ordering off a single advance. - Never use
UserDefaults(suiteName:)in a test. It writes a real plist into~/Library/Preferences, and cfprefsd rewrites it after the process has exited, soremovePersistentDomainintearDowndoes not stick. Two tests had left 826 of them on the maintainer's Mac before anyone looked. UseMemoryDefaultsfromIsolatedSettings.swift, and build models throughIsolatedSettings.model(), which is the one way a test gets an app model that touches nothing real. - Adding a setting is two places. A property on
SettingsValuesand a line in its hand-writteninit(from:). Forget the second and the field decodes as its default forever, silently, because the decoder is deliberately lenient so an older snapshot never fails to load. - The gate for "no singletons" is
static let shared, not.shared.grep -rn "\.shared" mac/Sourceswill always find Apple's own (NSWorkspace.shared,URLSession.shared). The one that means something isgrep -rn "static let shared\|static var shared" mac/Sources, which must print nothing. - Sender config writes are change-gated now. A setter used to rewrite
~/.agent-inbox/configunconditionally; nowsync()runs only when a sender-visible field actually changed.AppModel.start()still syncs once unconditionally, so a fresh launch always leaves the file current. - The delegate gets the model from the App, not from a global.
AgentInboxApp.initbuilds the model and setsdelegate.modelon the adaptor, which has already constructed the delegate by then; verified with a throwaway package rather than assumed. The optional is guarded with a precondition, so a future refactor that reorders this fails at launch loudly, which is the right failure. - Test the binary you think you are testing. A
--configureflag appeared to hang through several rounds of debugging because/Applicationsheld the released build, which predated the flag.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- today Changed · +90 lines · +1,603 tokens per session 600311c743fb
- 5d ago First seen · 116 lines · 1,483 tokens per session scan A a3972c9b8f52
agent-inbox CLAUDE.md is an instructions file published in the GitHub repository Ideaplaces/agent-inbox (3 stars, last pushed 3d ago), licensed MIT. It adds 3,086 tokens to every session, about $0.0154 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other instructions, from other repositories
best-claude-hud AGENTS.md
Instructions for GaoSSR/best-claude-hud, covering project agent instructions and release work.
localvoxtral AGENTS.md
AGENTS.md instructions for T0mSIlver/localvoxtral, covering localvoxtral — agent guide, build & test — read this first on a non-mac dev box, proof culture — non-negotiable, test tiers — the short version and ci / shipping.
apple-browsers pixels.instructions.md
Instructions for duckduckgo/apple-browsers, a project described as: DuckDuckGo iOS & macOS browsers.
ntfy-mcp-server AGENTS.md
AGENTS.md instructions for cyanheads/ntfy-mcp-server, covering developer protocol, what's next?, core rules, patterns and tool.
iOS-vibebuddy AGENTS.md
AGENTS.md instructions for semantic-craft/iOS-vibebuddy, covering agents.md, verification strategy, agent skills, issue tracker and triage labels.
Clipth AGENTS.md
Instructions for wavever/Clipth, covering agent.md, 这是什么, 目录结构, 本地构建运行 and 代码签名(动签名相关的任何东西前必读).