npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

agent-redline-ios

v0.1.9

Published

Installs Redline on your Mac: point at UI in a Debug build of your iOS app and send a note with a snapshot to the Claude Code or Codex chat working on it.

Downloads

1,427

Readme

Redline

Redline is a SwiftUI annotation tool for agentic iOS development. Add .redline() to your root view, run a Debug build on a device or simulator, and tap elements to annotate them. Reports route to your Claude Code or Codex session, optionally matched by worktree. Each snapshot carries the annotation plus every annotated element's accessibility label, role, and identifier. Your agent resolves views in source instead of inferring them from contextless pixels.

Version 0.1.9, early development. Works with Claude Code and Codex only.

How it works

Redline has two parts:

  • The kit: the Redline Swift package, which provides the .redline() modifier for your root view. It compiles into Debug builds only.
  • The Mac side: Redline.app, a menu bar app (the hub in the figures), and the redline command. Your sessions run it as an MCP server or hook, and you run it in Terminal.
  1. Your session registers its bundle IDs. Redline reads them from the app targets of the Xcode project, or XcodeGen project.yml, in the session's working directory. It accepts reports only for registered bundle IDs, and keeps them registered after the session closes.
  2. Redline sets up the build. It writes the Mac's address and a token to hub.json in the data container for the build's bundle ID. On an iPhone, it uses Xcode's device link, because a build can't find the Mac on its own.
  3. You send a report. Tap the floating button to enter annotate mode, then tap elements or draw around them, add notes and tap Send. On an iPhone, the build saves the report and sends it over the local network. On a simulator, Redline copies it out of the data container.
  4. Redline delivers it to your session. It files the report in its inbox, then sends it with each snapshot's path.

Steps 2 and 3 on a device and on a simulator:

How Redline works covers when Redline scans for devices and new installs, how it chooses and reaches a session, and what each report file holds.

What your agent receives

A report arrives in your session as a message like this one. Notes 1 and 2 match the figure at the top. Note 3 is on an attached photo.

UI report from Alex's iPhone · Sample Notes

/Users/alex/Library/Application Support/Redline/inbox/com.example.notes/20261004-142233-0E12001C/5E0C2A4B-7F1D-4C39-9A0E-2B6D8F41C3A7.jpg
1. Save (Button, editor.save): The button sits under the keyboard on small phones
2. Title (Text field, editor.title): Placeholder is hard to read in dark mode

/Users/alex/Library/Application Support/Redline/inbox/com.example.notes/20261004-142233-0E12001C/C81D3F07-52B6-4E8A-B19C-6A04D7E2F915.jpg
3. Photo: This is how it looked in the last build

Each snapshot's path comes first, then its notes, numbered like its outlines. A note reads Label (Role, identifier): note. An element without a label is named by its identifier. Any named ancestors follow, such as in Cell "Milestones" (today.list), so your agent can tell apart elements that share a label. A drawing's snapshot shows its strokes instead of an outline, and its note lists up to 12 named elements inside it, such as Drawing around Growth and 2 more, enclosing Text "Growth", Button "Weight" (growth.weight), Button "Length": Too cramped.

When a report goes through the Codex app, its snapshots arrive as attachments. Claude Code reads them from their paths. Each report folder also holds report.md with a summary and report.json with everything the kit read about each element, such as its frame, value and class.

Requirements

  • A Mac with macOS 15 or later.
  • Xcode 26 or later.
  • A SwiftUI app target with a deployment target of iOS 18 or later.
  • An Xcode project or XcodeGen project.yml in your session's working directory. Redline reads the bundle IDs from it.
  • Claude Code, Codex, or both. Claude Code also needs the claude command installed and signed in (see After installing).
  • For an iPhone: paired with the Mac in Xcode, and on the Mac's local network.

Install on the Mac

Install the Mac side in one of three ways. Each runs the same installer, install.sh, which builds Redline from source with your Xcode, so the first run takes a few minutes.

  1. Ask your agent. Open your Claude Code or Codex session in your project and paste:

    Install Redline from https://github.com/mericksters13/agent-redline-ios and add it to this app.

    Your agent follows INSTALL.md: it adds the package to your app target and .redline() to your root view, builds the project, and lists what's left. It hands you one command for the Mac side, npx agent-redline-ios, since agent safety checks don't let an agent run an installer that changes your Mac.

  2. npx installs the latest release. It needs Node.js 18 or later.

    npx agent-redline-ios
  3. curl builds the latest main.

    (f="$(mktemp)" && trap 'rm -f "$f"' EXIT && curl -fsSL https://raw.githubusercontent.com/mericksters13/agent-redline-ios/main/install.sh -o "$f" && bash "$f")

    To build another branch, tag or commit, put REDLINE_REF=<ref> before bash.

With --no-input, or when a coding agent or CI runs it, the installer never prompts and lists the remaining steps instead.

What the installer changes

The installer is safe to rerun and never runs sudo. When a step needs you first, such as accepting the Xcode license, it stops and prints the command. Run it, then rerun the installer.

  • Installs the redline command in ~/.local/bin. If that folder isn't on your PATH, it adds a line to ~/.zprofile for zsh. For other shells, the checklist gives the line to add.
  • Installs Redline.app in ~/Applications, with a login item that launches it from there (~/Library/LaunchAgents/com.agentredline.hub.plist). Don't move Redline.app.
  • For Claude Code, checks that the claude command is signed in and recent enough, and adds Redline's MCP server for all your projects (claude mcp add --scope user). In a terminal, it runs claude update and claude auth login for you when needed.
  • For Codex, adds one hook, "Report delivery", to ~/.codex/hooks.json, after backing the file up as hooks.json.before-redline. Your other hooks stay.
  • Keeps its source and build cache in ~/Library/Caches/Redline, and its log, reports and settings in ~/Library/Application Support/Redline.

The MCP server and hook are no-ops in projects that build no iOS app.

The installer ends with a checklist, each item marked Done, Needs you or Skipped, and saves it to ~/Library/Application Support/Redline/install-report.txt.

After installing

The checklist names the steps only you can take, each with its command. The usual ones:

  • Authenticate the claude command with claude auth login, or run claude update if it's too old for the Claude app. Redline uses it to start new Claude Code sessions and resume closed ones. Its sign-in is separate from the Claude app's.
  • Trust the Codex hook. In Codex, open /hooks and trust "Report delivery". Codex runs a new hook only after you trust it, and Codex sessions register through this hook.
  • Open a new terminal if the installer added ~/.local/bin to your PATH.

On first launch, macOS asks whether Redline may show notifications. If your projects live in ~/Documents, macOS also asks for access to that folder. Allow it: Redline reads each session's project folder to learn which bundle IDs it builds. If macOS reports a new background item, that is Redline's login item.

Check what is still missing

Run redline doctor from your app's project folder after installing, after an update, or when reports do not arrive. Use --project <folder> to select another project, and --agent claude or --agent codex to check a specific destination. By default, one working agent is enough. If this terminal cannot find redline, use ~/.local/bin/redline doctor first.

Doctor checks the Mac requirements for your first report:

  • The Redline Mac app is installed and running.
  • Redline can read the project's app targets, including their build-settings files.
  • Redline can write, read and remove a temporary file in its report inbox.
  • Redline can start its Bonjour discovery operation, which requires Local Network access.
  • A chat whose project builds the app is available through Codex's delivery handshake or a running Claude Code session's socket. A chat in another checkout of the same app counts too, just as it does in the report's chat picker. Connection failures are reported separately from a missing project chat.

File and network checks run inside the Redline Mac app, using that app's access. They do not borrow Terminal's permissions. Doctor creates and removes a temporary storage probe; it does not contact an iOS app, submit a report, send a chat message, change agent settings, or install anything. macOS may show an access prompt during a check. Allow it and rerun doctor. If access is blocked, doctor gives the relevant setting or file-access fix. An unavailable check stays incomplete.

Completed checks show a green check mark and Done; missing or incomplete steps show a red x and Incomplete, with an action. Notifications, login at startup and device connection are excluded.

Piped output keeps the marks and labels without color codes. Set NO_COLOR=1 to disable color in a terminal.

Doctor exits with 1 when a Mac requirement is incomplete and 0 when its Mac checks pass. It checks Mac setup; it does not verify iOS app integration, iOS permissions or report delivery. Once the Mac checks pass, send a note from your Debug app.

Try the demo

Examples/RedlineDemo is an Xcode project with .redline() on its root view, a UIKit screen and three planted UI bugs to find. Clone this repository, open a Claude Code or Codex session in it, and run Examples/RedlineDemo/RedlineDemo.xcodeproj on a device or simulator. Its README covers device signing and what to try.

Add Redline to your project

Add the package to your app target, then .redline() to your root view. If your agent installed Redline from the prompt above, it has done both.

  1. Add the package. In Xcode, choose File > Add Package Dependencies and enter https://github.com/mericksters13/agent-redline-ios.git. Choose Up to Next Minor Version from 0.1.1, and add the Redline library to your app target.

    In a Package.swift, the dependency is:

    .package(url: "https://github.com/mericksters13/agent-redline-ios.git", .upToNextMinor(from: "0.1.1"))
    // in the app target's dependencies:
    .product(name: "Redline", package: "agent-redline-ios")

    For XcodeGen and Tuist, see INSTALL.md.

  2. Add .redline() to your root view.

    import SwiftUI
    import Redline
    
    @main
    struct SampleApp: App {
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .redline()
            }
        }
    }

The kit needs no Info.plist keys, build settings or build phases. Don't wrap the call in #if DEBUG: in Release builds, .redline() returns the view unchanged (see What compiles into your build).

The first report sent from an iPhone triggers the one-time iOS local network prompt. Allow it, or reports can't reach the Mac. To set the prompt's text, add NSLocalNetworkUsageDescription to your Info.plist.

Send your first report

  1. Check that Redline is running: its icon is in the menu bar.
  2. Open a Claude Code or Codex session in your project. Redline detects open Claude Code sessions. A Codex session registers through the hook on your next message to it, once you have trusted the hook.
  3. Run a Debug build from Xcode on a device or simulator. The menu bar panel shows the device as Ready (iPhone) or Running (simulator). Redline picks up simulator installs as they happen and scans iPhones for new installs every 30 minutes. After the first install on an iPhone, click Quit in the panel and reopen Redline.app to scan now.
  4. In the build, tap the floating Redline button, tap an element, write a note and tap Add note.
  5. Tap Send. The first time, pick your session in Send to and confirm.
  6. The report arrives in your session, and the menu bar panel lists it with the session it went to.

Using Redline

In the build

  • Floating button. Tap it to enter annotate mode. Drag it anywhere; it snaps to the nearest edge. Press and hold it to list the reports sent from this device.
  • Annotate mode. Routes taps to Redline instead of the build, and draws a light red border around the screen. Its controls sit in a black bar at the top. The bar hides while your finger is on the screen, so you can see what is under it: touch anywhere and slide onto the element.
    • Tap an element to select it. The note card identifies that element and offers View hierarchy.
    • Tap View hierarchy to browse the nearest captured owner and its children, with your selected component highlighted inside it. This includes the owner of a group you tapped. The tree stops at that owner; when none is captured or it covers almost the whole screen, the selected element is the root. Indentation and vertical lines show which nodes own their children; arrows fold and unfold branches. Tap a row to move the outline and note target, then Done to return to your draft. Browsing keeps the same tree and excludes unrelated sections. Only children exposed in the captured accessibility tree appear. To expose a card or section, see Make containers pickable.
    • Write a note and tap Add note. Notes collect across screens until you send them.
    • Tap the pen in the bar to draw instead, for example to circle a gap or a group of elements. While you draw, the bar shows Undo and Done, and its close button discards the drawing. Tap Done to number the drawing and write its note. The note card lists the named elements inside the drawing; its Cancel returns to the drawing with your strokes kept.
    • Tap the close button in the bar to exit annotate mode. Unsent notes stay.
  • Notes tray. Lists unsent notes; tap the screen name in the bar to open it. Tap a note to view it full screen with its snapshot, or tap its trash button to delete it. Unsent notes persist on the device, across a killed process and a reinstall from a rebuild.
  • Screenshots and photos.
    • Take a screenshot. A thumbnail appears beside the floating button; tap it to add a note and send. Redline captures the build's own windows at that moment, so its overlay never appears in the snapshot. With Photos access, the thumbnail switches to the screenshot you saved once it reaches Photos, so a crop or markup from the system's editor is what you send. That one is the system's screenshot, with Redline's button or bar where they were on screen.
    • In annotate mode, the capture button attaches a snapshot of the whole screen, and the paperclip opens a photo panel. Without Photos access, the panel offers PhotosPicker, which needs no permission.
    • If your Info.plist has NSPhotoLibraryUsageDescription, the panel can show recent photos: tap Show recent photos to request access. With access, Redline also offers screenshots you took in other apps when you return to the build, and the saved copy of one you took in the build.
    • Element notes and attachments go out together in one report.
  • Send to. The Send to row in the notes tray sets where reports go. Tap it, choose an agent, then one of its sessions that work on this bundle ID, or New chat. The picker lists open Claude Code sessions and Codex sessions used in the last 14 days. The session in the build's worktree comes first, tagged "This build", and is selected. The first Send from a worktree asks you to pick; later builds from it keep the pick. Where reports go explains each choice.
  • Delivery. After Send, a toast says whether the report reached the Mac. Undelivered reports stay on the device, and the build retries them on launch, on each return to the foreground, and with the next Send. The sent reports list marks each report "On the Mac" or gives the reason it isn't there yet.

Make containers pickable

Redline picks from your build's accessibility tree. Buttons, text and controls are always in it. A card, section or custom component built from stacks usually isn't, so it's missing from the path in the note card. One modifier makes it pickable, and a second names it.

The accessibility tree. iOS describes each screen to assistive technologies such as VoiceOver as a tree of elements. Each element has a frame, a label (what VoiceOver reads), traits such as Button or Header, and optionally an identifier. SwiftUI builds this tree from your view hierarchy, but not one to one: layout containers such as VStack, HStack and Grid get no element of their own, so their children sit directly under the nearest element above them. In Debug builds the kit turns on the automation mode XCUITest uses, so SwiftUI builds the tree even with VoiceOver off.

Accessibility identifiers. An accessibilityIdentifier is a string for code, not for people. VoiceOver never reads it, and it doesn't change when your copy or language does. UI tests use it to find elements. Redline puts it in each note, Label (Role, identifier), so your agent searches your source for it instead of guessing from display text that can repeat or be localized.

What you can pick. A tap selects the innermost element under your finger. View hierarchy opens its nearest captured group; tap a row in that tree to select it. A container with no element of its own isn't in the tree.

Give a container an element of its own. Add both modifiers to the container:

VStack(alignment: .leading) {
    Text(recipe.name)
    Text(recipe.summary)
}
.accessibilityElement(children: .contain)
.accessibilityIdentifier("detail.titles")

.contain makes the stack an element that keeps its children pickable, and the identifier names it. Tap a child, then View hierarchy to browse detail.titles; tap its group row to select the whole stack.

With .contain alone, the stack is pickable but has no name of its own, so Redline names it after what it holds, such as "Lemon Herb Chicken" and "Weeknight dinner…", and the report lists those names for your agent to search for. The identifier gives your agent something exact. The earlier compact-path UI in the demo, with and without the two modifiers:

When .contain adds no element. SwiftUI creates a new element when the container holds several elements, none, or one element with no children. When it wraps exactly one element that already has children, such as a single card that is already a container, SwiftUI changes that element instead, so the hierarchy gains no new level. Put the modifiers on that inner element.

These modifiers ship in your Release build. Redline is Debug-only, but the modifiers are part of your views. .contain makes VoiceOver move through the container's children together before the next element, so add it where the views form one group, such as a card or a form section, and check the order with VoiceOver. An identifier changes nothing VoiceOver reads.

Set both, not just the identifier. On a container with no element of its own, SwiftUI copies the identifier onto each child instead of naming the container. In the demo, .accessibilityIdentifier("detail.stats") alone on the stats grid left the grid out of the path and gave every stat cell the identifier detail.stats.

What merges or hides elements:

  • .accessibilityElement(children: .combine) merges a container's children into one element. The demo's stat cells use it, so a tap selects the whole cell, not its title or value.
  • .accessibilityElement(children: .ignore) replaces the children with one element that you label.
  • A Button or NavigationLink can merge its label into one element. The demo keeps its custom RecipeRow outside a NavigationLink label and uses .accessibilityElement(children: .contain) on the cell itself. Each row exposes its icon, a nested title-and-summary group, and its duration. Tapping the row opens the recipe; the title also has a default accessibility action and button trait so assistive technologies can open it.
  • .accessibilityHidden(true) removes a view and its children. Redline also skips views that are hidden, nearly transparent, or clipped out of view.
  • Canvas, Metal and custom drawing have no child elements. To make their parts pickable, give the view synthetic children with accessibilityChildren(children:), such as one per bar of a chart, or replace its elements with accessibilityRepresentation(representation:). Redline outlines each synthetic child at the frame of the view that describes it, and the path leads out to the drawing. Otherwise, pick the enclosing view, or attach a snapshot of the whole screen with the capture button.

UIKit. Set accessibilityIdentifier on the view. A view with an identifier or a label becomes a group in the path; set isAccessibilityElement = true to make it one element instead.

Apple's documentation: Accessibility fundamentals, accessibilityIdentifier(_:), accessibilityElement(children:), AccessibilityChildBehavior, accessibilityChildren(children:), accessibilityRepresentation(representation:), and UIKit's accessibilityIdentifier.

On the Mac

Click the Redline icon in the menu bar to open the panel:

  • Devices: paired iPhones, and running simulators with one of your builds installed, each with its last report. An iPhone that can't take reports right now is dimmed, with the reason, such as Not reachable or No watched app installed.
  • Agents: Claude Code and Codex, whichever are installed, and whether reports can reach their sessions right now. When they can't, the row says what happens to reports meanwhile and what to do: for Claude Code, a command with a button that copies it; for Codex, open or reopen the Codex app.
  • Reports: the 30 newest, each with its first snapshot, device, arrival time, the session it went to (or why it is waiting) and its first notes. Click one to see its snapshots and notes side by side. Open in Claude Code or Open in Codex reopens that session, and Show in Finder shows the report folder.
  • At the bottom, Open inbox opens the inbox folder, and Quit stops Redline.

Each report also posts a macOS notification that says where it went.

Where reports go

A report goes to the session you picked in Send to. With no pick, Redline uses the build's worktree, found from the #filePath that .redline() captures at compile time:

  • One session works there: the report goes to it.
  • No session works there: Redline starts a new one.
  • Several sessions work there, or the worktree isn't on this Mac, such as for a build made on another Mac: the report waits in the inbox until a session takes it (see Troubleshooting).

New sessions. Redline creates a worktree from your repository's main branch, on a branch named report/<report ID>, and starts the session there. A new Codex session uses codex exec in a read-only sandbox only to create the chat, then releases it before the Codex app opens it and receives the report with its snapshots. Without the Codex app, the command looks into the report before opening the session in Terminal. A new Claude Code session opens in the Claude app and receives the report there, with your usual permission settings. Without its agent's app, a new session opens in Terminal.

  • A new session starts from main, not from the build's branch. When the build's worktree isn't on main, the picker says so under New chat, such as "Built from feature/growth-card. A new chat starts from main." If the bug exists only on that branch, pick that branch's session instead.
  • With no pick, Redline uses the agent you last used for this bundle ID, or else the first agent that can start a session. Picking New chat lets you choose the agent, and later reports with that pick go to the same session. Picking New chat again starts another.
  • A new session needs its agent's command, claude or codex, and a main branch to start from. When no session can start, the report waits in the inbox.

How each agent receives a report.

  • Claude Code. The report starts a turn in the session, even when it is idle. If the session has closed, Redline first resumes it with claude --resume, in the Claude app or in Terminal.
  • Codex. The report starts a turn through the Codex app. If no window shows the session, Redline opens it first. If the Codex app isn't running or doesn't respond, the "Report delivery" hook adds the report to your next message in that session. Redline reaches the Codex app through its IPC socket, whose protocol Codex doesn't publish, so a Codex update can break this path until you update Redline. The hook keeps working meanwhile.

What compiles into your build

  • Debug builds only. Package.swift defines the kit's REDLINE compile flag for the Debug configuration only. Release builds, including TestFlight and App Store builds, get an empty module: .redline() returns the view unchanged, and your source file path isn't kept in the binary.
  • A private API, in Debug only. SwiftUI builds its accessibility tree only while an assistive technology is connected. To read accessibility labels and roles, the kit enables the automation mode XCUITest uses, through the private function AXSSetAutomationEnabled, resolved with dlsym at run time. Release builds don't contain it.
  • No Mac code. The redline executable, which Redline.app wraps, is a separate product in the same package. Your app target links only the Redline library.

Privacy and security

  • Local network only. Redline has no cloud service and no account. An iPhone sends reports to your Mac over your local network, on TCP port 47361. On a simulator, Redline copies them out of the data container on the same Mac. To fill Send to, Redline sends the build the sessions that work on its bundle ID (titles, folder names and last activity) and the branch of its worktree.
  • Plain TCP, with a token per iPhone and bundle ID. The connection isn't encrypted, so others on your local network could read a report in transit. Redline generates a random token for each bundle ID on each iPhone and writes it to the data container over Xcode's device link, which only a Mac paired with that iPhone can use. Both sides prove they hold the token with an HMAC-SHA256 challenge-response, so the token itself never crosses the network. The build sends reports only to the Mac that set it up, and Redline rejects anything else. Tokens live in ~/Library/Application Support/Redline/hub/tokens.json, with mode 0600.
  • Internet use. Redline itself goes online only to create a worktree for a new session: it asks your repository's origin for its main branch and fetches it. Agents it starts use the network as they normally do.
  • Where reports are kept. On the device, in the data container under Library/Application Support/Redline. The build keeps every report the Mac hasn't confirmed, plus the 20 newest confirmed ones. On the Mac, in ~/Library/Application Support/Redline/inbox, never deleted automatically. A new Claude Code session also gets a copy of its report in its worktree's .redline folder, which git ignores.
  • What your agent sees. A delivered report enters the session's context like any other message. Snapshots show whatever was on screen, so don't annotate screens with personal data you don't want in a session.

Update and uninstall

Update

Update the Mac first, then your projects. An older Redline on the Mac still delivers reports from a newer kit, but may not read them fully.

  • Mac. Rerun your install command. It rebuilds and restarts Redline. The curl command builds the latest main. With npx, request @latest, or npx may reuse its cached copy:

    npx agent-redline-ios@latest
  • Project. In Xcode, choose File > Packages > Update to Latest Package Versions, then rebuild.

Uninstall

Run either command:

npx agent-redline-ios uninstall
(f="$(mktemp)" && trap 'rm -f "$f"' EXIT && curl -fsSL https://raw.githubusercontent.com/mericksters13/agent-redline-ios/main/install.sh -o "$f" && bash "$f" uninstall)

Uninstalling removes the redline command, Redline.app, the login item, Redline's hooks and MCP entry, the line it added to ~/.zprofile, and its cache in ~/Library/Caches/Redline. The checklist lists anything it couldn't remove. Other tools' hooks and MCP servers stay, as do:

  • your reports, in ~/Library/Application Support/Redline
  • the .before-redline backups, next to the files they copied
  • the worktrees and report/ branches made for new sessions, and the line Redline added to each repository's .git/info/exclude

In your project, remove the .redline() call and the package.

Troubleshooting

Start with redline status and the menu bar panel. Both show each iPhone's state and the reports in the inbox. Redline logs to ~/Library/Application Support/Redline/hub/hub.log.

The build shows "Saved on this iPhone. Couldn't reach the Mac". The build couldn't connect to Redline: Redline isn't running, the Mac is asleep or on a different network from the iPhone, or the build's Local Network access is off (turn it on in Settings > Privacy & Security > Local Network). The report stays on the iPhone, and the build retries it on launch, on return to the foreground and with the next Send. redline status shows the addresses builds use to reach the Mac.

The panel shows an iPhone as Not reachable. Redline couldn't reach the iPhone over Xcode's device link: it is asleep, out of range or on a different network. Wake it. Redline keeps retrying, and retries immediately when the iPhone wakes.

The build shows "Not on the Mac yet: no Mac has set up this app", or the panel shows No watched app installed. Redline hasn't found the build on that device yet. It picks up simulator installs as they happen. For an iPhone, it scans for new installs when it starts, when a session for a new bundle ID opens, and every 30 minutes. To scan now, click Quit in the panel and reopen Redline.app from ~/Applications. If it still doesn't find the build, check that a session for the project is open (for Codex, trust "Report delivery" in /hooks, then send the session a message) and that Xcode can reach the iPhone.

Annotate mode says "SwiftUI elements may not be pickable". The kit couldn't enable the automation mode SwiftUI needs (see What compiles into your build), most likely because this iOS version removed the private function it uses. You can still select UIKit views, and the capture button still attaches a snapshot of the whole screen.

macOS asks about your Documents folder again after you update Redline. The installer signs Redline with your Apple Development certificate when it can use one. Without one, Redline is signed ad hoc, so macOS may ask again after each rebuild. Allow it.

Reports for a Codex session wait for your next message. The Codex app isn't installed, isn't running or doesn't respond. The Agents row in the panel says which. Open the Codex app. If it still doesn't respond after you reopen it, a Codex update may have changed how Redline reaches it: update Redline. If reports never arrive at all, open /hooks in Codex and trust "Report delivery". If you installed Codex after Redline, run ~/.local/bin/redline setup.

A notification says to run claude auth login. The claude command, which starts new Claude Code sessions and resumes closed ones, isn't signed in or is too old for the Claude app. The report waits in the inbox, and Redline delivers it once the command is ready. Run claude auth login, or ~/.local/bin/redline setup, which checks both.

A report waits in the inbox. The panel says why, for example when several sessions work in the same worktree and none was picked. Pick a session in Send to for the next report. To deliver the waiting ones, ask a session to call check_messages (Claude Code sessions started after the install) or to run redline check in the project folder.

"Couldn't find devicectl." Install Xcode and select it: sudo xcode-select -s /Applications/Xcode.app.

Command reference

| Command | What it does | |---|---| | redline doctor [--project <folder>] [--agent claude \| codex] | Checks the Mac requirements for a first report and lists missing steps with actions. | | redline status | Shows whether Redline is running, the bundle IDs it accepts, the addresses and port builds connect to, each iPhone's state and the inbox. | | redline check | Prints the reports waiting for this project's bundle IDs. Printing claims them, so no other session receives them. | | redline wait | Waits for the next report for this project's bundle IDs, then prints it. | | redline setup | Checks the claude command and adds the Codex hook. With --no-input, or without a terminal, it lists the commands for you to run instead of running them. | | redline remove | Removes Redline's hooks. Other hooks stay. | | redline mcp | Runs the MCP server for Claude Code sessions, with the check_messages and wait_for_message tools. | | redline hub | Runs Redline without the menu bar app. | | redline app | Runs the menu bar app, as opening Redline.app does. |

check, wait and mcp take --project <folder>, and --app <bundle ID> when the bundle ID can't be read from the project. hub and app take --app <bundle ID> to accept reports for a bundle ID no session works on.

Contributing

CONTRIBUTING.md covers building, testing, installing your own checkout and sending a change. docs/CODE_STYLE.md sets the code style.

Acknowledgements

The kit's accessibility tree traversal and its automation switch follow the approach of AnnotateKit (MIT).

License

Redline is released under the MIT License.