Skip to content
CarolaneLFBVPublic

About

Xcode's built-in Claude agent, watched from the notch of your MacBook Pro. Read-only, no network, no persistence.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Perch

Perch

Perch shows the state of Xcode's built-in coding agent — Claude or Codex — in the notch of a MacBook Pro.

Idle, there is nothing: the notch goes back to being a notch. The moment the agent starts working, two hairlines frame it — the running tool on the left, the project on the right. Hovering unfolds a panel beneath the camera housing: project, branch, model, context in use, session token totals, the Codex quota if one exists, conversation title, the Xcode run destination if it answers, and the last tools called.

The Perch panel unfolded under the notch, showing project, branch, model, Xcode version, context, session totals, conversation title and recent tools

Perch watches. It drives nothing, writes nowhere, and connects to nothing.

What you need

Perch needs Xcode's built-in coding agent. Without it, it shows nothing — ever, and without an error message.

Both agents Xcode ships are supported, and whichever wrote most recently is the one on screen:

~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/projects/
~/Library/Developer/Xcode/CodingAssistant/codex/sessions/

These directories only exist once Xcode has launched that agent at least once. An agent installed by hand and started from a terminal writes elsewhere and will not light Perch up: it is not the same one, and Perch tells them apart by the executable's path.

A Codex session shows a Quota row where a Claude one shows Title, and not the other way around: Codex records no conversation title, and a Claude transcript carries no rate-limit window to show. The row count is the same; only which row appears differs.

No Xcode version number is ever tested. Perch was developed against Xcode 27 and works the same way on Xcode 26 — the layout under CodingAssistant/ is shared across versions, and the per-build component of the agent's path is deliberately ignored. What would break Perch is Apple moving that directory or changing the transcript format, not a new Xcode release.

The rest: macOS 14 or later, a Mac with a notch (on a notchless display Perch stays silent rather than relocating), and a Swift 6 toolchain. No external dependencies.

Install

Download Perch.dmg, open it, and drag Perch into Applications. It is signed and notarised by Apple, so a double click is all it takes — no security warning, no right-click trick, no trip through System Settings.

That link always serves the newest build. Older versions are kept under their own names on the releases page.

Drag it to Applications rather than running it from Downloads: the permission you grant it is tied to where the app lives, and moving it later means granting it again.

Updating

Quit Perch, drag the new version into Applications over the old one, launch it again. There is no uninstaller, and no update setting — Perch opens no network connection, so it cannot tell you a new version exists. The download link above always serves the newest one.

The permission you granted survives the update. macOS identifies an app by its bundle identifier and the designated requirement of its signature, both of which stay the same from one signed release to the next, so it will not ask again.

Building it yourself

bash Scripts/bundle.sh && open build/Perch.app

Builds in release, assembles the .app and signs it ad hoc — enough to run locally, not enough to hand to anyone else. The bundle is not optional: it carries the NSAppleEventsUsageDescription key, without which macOS kills the process on the first Apple Event sent to Xcode. The details are commented at the top of Scripts/bundle.sh.

Producing a distributable build takes a Developer ID and a trip through Apple's notary service; Scripts/package.sh does the whole run and documents each step.

The About window

Perch has no Dock icon and no window of its own — the notch panel ignores mouse events and disappears entirely when the agent is idle. A bird icon appears in the menu bar; its menu opens an About window carrying the version, a language selector, a link to this repository and a Quit button.

The interface speaks 11 languages: English, French, German, Spanish, Italian, Brazilian Portuguese, Dutch, Japanese, Simplified Chinese, Korean and Russian. On first launch Perch follows the system language; the selector overrides it and relaunches the app, which is what applies the change. The ad hoc signature keeps the Xcode permission across that relaunch, so switching costs no prompt.

Translations for languages the author does not read were written without a native reviewer. Corrections are welcome — one file per language under Sources/Perch/Resources/<code>.lproj/.

perch-cli stays English whatever the setting: its output is meant to be pasted verbatim into an issue.

Quitting

Click the bird in the menu bar, then Quit Perch — or use the Quit button in the About window. Either is a clean stop, and both let Perch close what it opened. pkill does not: it short-circuits the teardown.

The permission prompt on first poll

The first time Xcode is queried — within seconds of launch, if Xcode is running — macOS asks for permission for Perch to "control Xcode". It is used solely to read the active scheme and run destination, and nothing else goes through that channel. Deny it and Perch keeps working: the Target row simply disappears from the panel.

The script's ad hoc signature makes that permission stick from one launch to the next. It is asked again after every rebuild: the signature follows the binary, which changes as soon as the code does.

When nothing shows up

Run the diagnostic before anything else:

swift run perch-cli

It reads the same data as the app, in a single pass, and reports what it found: the sessions directory, the running agent, the age of the last transcript, the model, the project, the counters. Its output is designed to be pasted as-is into an issue: it contains no message content, no full path, no user name, and no device name.

Two answers explain nearly every case:

  • Sessions directories : MISSING — no Xcode agent has ever run on this machine. See "What you need" above.
  • No recent session — the directory exists but no transcript has been written in the last hour. Perch does not look further back: a day-old session is not a state worth showing.

Privacy

Perch is read-only and keeps nothing.

  • Transcripts are opened read-only, and the descriptor watching for writes is O_EVTONLY: nothing is ever written into the agent's directory.
  • Only metadata is decoded: token counters, model name, tool names and identifiers, project path, git branch, timestamps, and — for a Codex session — the rate-limit window's used percentage and reset time. Message text, tool arguments, and tool results are not decoded at all.
  • Nothing is persisted, logged, or exported. Perch writes no file, has no database or on-disk cache, logs nothing, and opens no network connection. State lives in memory and dies with the process.
  • The project's only textual output is perch-cli's, which deliberately masks the transcript directory's name (it encodes the project's absolute path, account name included), the Xcode run destination's name (for a physical device it conventionally contains its owner's first name), and the conversation title, whether derived from the first message or written by hand — that one can name a client or a product. The notch displays them: it is your screen. The CLI's output, by contrast, is made to be pasted as-is into a public issue.

Tests

swift test
swift build -Xswiftc -strict-concurrency=complete

All of the reading logic lives in XcodeAgentKit, a module with no dependency on the interface, testable without launching the app or touching Xcode.

License

MIT — see LICENSE.

About

Xcode's built-in Claude agent, watched from the notch of your MacBook Pro. Read-only, no network, no persistence.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages