luke AGENTS.md

A set of repository instructions for Luke, a macOS-first Electron application that observes coding-agent sessions. It explains the split between desktop apps and reusable packages, plus the project's build and validation commands.

In plain words
What is it for?
Bootstrapping dependencies, running checks, testing the macOS app, launching it with live or fixture sessions, creating signed release packages, and collecting verification evidence.
Why use it?
It keeps the desktop shell thin and reusable code platform-independent. It also gives agents a defined process for testing, packaging, signing, and visually validating the app.

Instructions file for CodexOpenCode

Install

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.

agentmods
npx agentmods add instructions/reviewstage/luke/agents-md
Clone the repo
git clone --depth 1 https://github.com/ReviewStage/luke

Made for: Codex, OpenCode.

Per session 11,029 This file is loaded in full into every session.
When invoked 11,029 The same file — it is already loaded in full.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

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.

ModelPer sessionOnce invoked
Fable 5 $0.11029 $0.11029
Opus 5 $0.05514 $0.05514
Sonnet 5 $0.02206 $0.02206
Haiku 4.5 $0.01103 $0.01103

Measured 3d ago against content hash 271290cc68cb, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

luke AGENTS.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 3d ago.

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.

AGENTS.md · 703 lines

How it starts

The opening of the file, as written. The whole thing — 703 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Agent guide

Luke is a macOS-first Electron sidecar that observes coding-agent sessions while preserving existing provider workflows. Product naming belongs at the app and packaging boundary; keep reusable implementation types brand-neutral. Deployable products belong in apps/, and reusable packages belong in packages/. Keep Electron main/preload code in apps/desktop/ thin, keep the renderer sandboxed, and put platform-independent behavior in packages/.

Canonical commands:

Command What it does
./scripts/bootstrap.sh Install pinned workspace dependencies
./scripts/check.sh Run portable repository, type, test, and build checks
./scripts/test-macos.sh Package and validate the macOS app
./scripts/verify.sh Complete macOS validation plus visual evidence
pnpm release:macos Create a local signed, notarized, and verified electron-builder DMG, zip, and update manifest
./scripts/run.sh Launch the app against live sessions, replacing any running instance (--fixture smoke for fixture data, --keep-running to keep the running instance, --no-trace to skip the development trace)
./scripts/evidence.sh Write the fixture PNG under artifacts/
pnpm evidence:record Record the fixture transition on a physical Mac
pnpm lint:fix Apply repository formatting and safe lint fixes

Trust constraints:

  • Never write provider transcripts or session-state files. Reading them is what Luke is for; writing to them is never.
  • Never inject terminal input, simulate keystrokes, or request Accessibility. A message the developer explicitly sends through Superset's documented terminals send command is not terminal injection: Superset owns the terminal and its authenticated endpoint, the observed binding identifies the exact target, and Luke invokes it directly without a shell. It remains bound by the same direct-user-act and latest-roster validation as every other session message.
  • A Superset workspace creation is the same bounded exception at the workspace level: only in a developer-opened turn, only on a host, project, and agent preset returned by the CLI's latest read, and only through the documented workspaces create command invoked directly without a shell. Luke supplies the developer's opening task and a bounded generated branch, then may call workspaces open for the identifier that creation returned. Renaming a workspace is the same exception narrower still: only in a developer-opened turn, only on a workspace behind an observed roster row, and only through the documented workspaces update command invoked directly without a shell, carrying nothing but that workspace's observed id and host and the developer's own bounded new name behind --name, never the command's other flags, which link and unlink tasks this exception does not authorize touching. The connection itself is bounded the same way at both ends: Connect runs the CLI's own auth login and Disconnect its documented auth logout, each only at the developer's press on the Superset row, each invoked directly with arguments fixed by the build, and the CLI owns the credential throughout. One deletion is authorized, as the control a managed row advertises and nothing wider: deleting the workspace behind that row, through the documented workspaces delete command with the observed workspace id as its single argument, invoked directly without a shell, only as the direct product of the control's own press or a developer-opened turn, and advertised only on a row positively seen settled, never one still working or unreadable, because the delete is unrecoverable and takes every sibling chat's terminal with it. A managed row here is also the standing row an idle workspace earns for itself: a worktree with no agent terminal at all, read from the same observed host state, is settled by construction, since there is no agent whose turn could be cut, and a workspace whose only terminal Luke cannot map draws no row rather than a gamble, while the main checkout and anything Superset already archived stand behind no row and can never be offered the delete. This does not authorize any other Superset CLI command, deletion of anything else, tasks, automations, account changes, or settings changes.
  • Product behavior must not require provider MCP, plugins, hooks, wrappers, credentials, or live sessions. A provider whose sessions exist only in a cloud service may read a user-supplied API key, but it must observe nothing until the user supplies one and must leave every other provider working without it.
  • A cloud surface that documents no key-scoped API and answers only its own CLI (Codex cloud today) is observed through that CLI instead, and the rule keeps its shape at one remove. Observation runs the provider's own binary with a read invocation fixed by the build, under the login the user already gave that CLI for its own sake: the credential never passes through Luke, no token is read, stored, or forwarded, and the CLI answers exactly as it would in the user's own terminal. No shell stands between Luke and the binary, nothing enters an invocation's arguments beyond values the build fixed (or, for a paged read, the bounded page cursor the same read's previous page handed back, as a single token), and a machine whose CLI is absent or signed out is observed as having nothing, the same answer a key-observed provider gives with no key. The login is the consent, given by the user's own hands to the provider itself, and signing the CLI out withdraws it on the next pass. Writes keep the shape every provider write has, at one remove: the one write Luke makes through a provider CLI is a new Codex cloud task the user just asked for, through the CLI's own documented creation command, in an environment the latest observation pass reported. The ask carries the developer's own task text as a single argument behind an end-of-options separator, never through a shell, under the same login, probed again at the moment of the act, and the one thing read out of the answer is the created task's id, for the next pass to report on its own. Codex documents no way to message or steer a task already running, so its cloud sessions advertise none, and the honest absence stands rather than an improvised control. Widening the invocation set further, or observing another provider this way, is a product decision, not an implementation detail.
  • A message to a local Cursor chat is the same bounded CLI exception at one remove: Cursor's own cursor-agent CLI documents resuming a chat by id and taking one prompt non-interactively, so the one write Luke makes through it is the message the developer just asked to send to a chat the latest observation advertised for one. The advertisement itself is bounded on every side — the turn is settled, because a resume into an open turn would race it; the folder is the one Cursor's own workspace record names, because the resume must be pinned there with --workspace or the CLI forks the chat's transcript under the invoking directory's project; the CLI is installed; and the Cursor app does not hold the chat, because Cursor does not document whether an app window shows a turn landed behind it, and a message the developer cannot see land is worse than none. The invocation is direct without a shell, its arguments fixed by the build beside the observed chat id, the observed folder, and the developer's own words as a single argument behind an end-of-options separator. The moment of the act re-checks what the advertisement rested on: the login is probed again by exit code alone, and the chat's transcript must still stand, because the CLI silently starts a fresh chat under an id it does not know, so a stale id must refuse rather than fork. Nothing is read out of the launched turn — the transcript observation already reads is the report — and a turn that outlives the short refusal window is a delivered message, never a process to kill. This authorizes no other cursor-agent command; widening it is a product decision, not an implementation detail.
  • Herdr, the terminal multiplexer coding agents run inside, is the one local surface observed through its own CLI, because its state lives inside its server and the CLI is the documented read of it — the Codex cloud rule kept its shape at one remove, here with no login at all. The reads are two: session list --json, the CLI's client-side enumeration of its named sessions, which answers with no server and starts none, and, for each session that enumeration reported running, agent list behind a --session carrying that session's own name, re-validated against the charset Herdr itself enforces before it may ride the invocation. No shell stands between Luke and the binary, no server is ever started — a server_not_running answer is a machine observed as holding nothing, the same answer an absent binary gives — and of each agent record one thing is kept: the hosted session reference Herdr's own integrations recorded, the id that joins a pane to a session Luke already observes from that provider's own files. What the join earns is an association chip on the row Luke already draws, never a row of Herdr's own — a Herdr pane's session is its provider's session, and a pane Herdr cannot name a session for draws nothing rather than a gamble. No write command of Herdr's is ever invoked, and its sessions advertise nothing to write with. Widening the invocation set, or the agent kinds the join reads, is a product decision, not an implementation detail.
  • One registration is the exception the previous rule's word "require" leaves room for, and it is bounded on every side: Luke may join an observation hook to a provider's own user-level hook surface (today the settings.json of Claude Code and Gemini CLI, the hooks.json of Codex and Cursor, Devin's config.json, and OpenCode's plugin directory, and nothing else of any provider's) so local rows can tell a turn that just ended from a session walked away from, and can see a tool call holding for permission at all. The hook itself writes one fixed status token into a spool under Luke's own application data, named by the session's id; the envelope the provider hands it — piped in, passed as an argument, or handed over in process — is read only for that id and never reaches disk. The merge preserves the user's own entries and settings as parsed, recognizes its own entries by the script's name, refuses to rewrite a file it cannot parse, converges at launch rather than accumulating, and skips a machine with no provider home to join. OpenCode's registration is the same exception in a different shape, and the difference is one of character, named here deliberately: OpenCode has no hook configuration to merge an entry into — it loads whole plugin files from its own plugin directory and runs them inside its own process, not as a process beside it — so Luke's one artifact there is one managed plugin file, generated by the build, recognized by the marker in its own header, converged at launch, and removed whole; a foreign file wearing its name is never rewritten or deleted, and the arrangement quietly installs nothing. The plugin is bounded exactly like the scripts: it writes one fixed token into Luke's own spool, reads nothing from an event beyond the session id it names (and, for a message event, which role wrote it, the same one-field filter the scripts apply to a subagent's envelope), lets no failure escape into the session that fired it, and goes silent the moment the spool is gone. The registration is part of observing at all, like reading the transcripts, so it converges at every launch rather than answering to a preference; an entry outliving Luke is a guarded no-op, and everything the hook sharpens still observes from the transcripts alone wherever the hook is absent, including behind Codex's own review gate, which shows a new entry to the user and runs nothing until they trust it. Widening it to another provider or another lifecycle event is a product decision, not an implementation detail.
  • The one thing Luke may change about a session is what the user just asked to send it: a message typed on its row, a control its provider advertised for it, or the same two acts asked of Luke, out loud or typed into his own composer, in a conversation the user is holding, each through the provider's own documented endpoint under the same user-supplied credential, and each validated against the observed roster before an adapter sees it. Observation passes stay read-only by construction; where a provider's documented read answers only a POSTed query (Conductor's transcripts view, like Linear's GraphQL), observation sends a read document fixed by the build, and nothing enters that document's text but identifiers the same pass reported, each validated against the shape its provider documents. Nothing that decides on the user's behalf may reach a write path: the attention evaluator above all, and every turn Luke opens himself (a proactive readout, the reply that voices a tool's outcome) which carries no tools, at the API and again at a runtime gate, so a session summary or a tool output that reads like an instruction can never become an act. A tool call in that conversation runs only in a turn the developer opened themselves, by speaking or by typing; a write is the direct product of a turn the developer opened, never of anything Luke read or was told. The one act not aimed at an existing session keeps the same shape: a new workspace, asked of Luke in conversation, lands only in a project its provider reported on the latest observation pass and documents a creation endpoint for; the ask names a reported project, never a repository URL or path of its own, and a provider that documents no such endpoint offers nowhere to create. A local manager's documented creation endpoint may be its own deep link rather than a network call: for a workspace on this machine (Conductor today) the ask is honored by handing that link to the operating system the way an open is, except that where an open reaches no provider this one asks the manager to make exactly what the developer asked. The project it names is still a reported one — a repository that manager's own index listed on the latest pass — and the path the create lands on is the one that report carried, read back from the offered project rather than composed by the ask; a manager that lists no repository offers nowhere to create, and the link carries the opening task alone, since Conductor's creation link documents no agent, model, or name. The ask may carry the new agent's opening task, the developer's own words, bounded and delivered like a message to an existing session, through the provider's documented endpoints, and each project says whether it takes one, needs one, or takes none, so a provider that cannot make an idle workspace is offered no task-less ask and one that takes no task is handed none. Another agent in a workspace already observed is the same ask at one remove: it lands only in the workspace behind a roster row, as one of the agent kinds that row's latest observation listed, through the provider's documented endpoint; a session whose provider lists none takes no such ask. A session whose provider documents no way in, or whose current state is documented for none, advertises nothing and is offered nothing; local sessions have no such endpoint and stay entirely read-only. Opening a session (its row pressed, the same press asked of Luke in conversation, or the notice popup announcing it pressed under the housing) is not a write and needs no endpoint: the address its provider reported is handed to the operating system, and nothing reaches the provider; an open asked of Luke still runs only in a developer-opened turn, and a session that reported no address is offered nowhere to open; its popup's press opens Luke's own panel instead, which touches no provider at all. A workspace Luke just created opens itself the same way: the creation ask, already a developer-opened turn, is also the ask to be taken there, so the session id the provider's creation response named (the one thing read out of that response that outlives the adapter, an identifier and never an address) is held briefly, and the first observation pass to report that session with an address hands the address to the operating system exactly once, as a row press would. Nothing a model decided can start that wait, and a created session that reports no address inside its window is left unopened like any other row without one. Reading a local session's transcript in conversation is the same shape of act: asked of Luke in a turn the developer opened, validated against the observed roster in the renderer and again in the main process, read from the provider's own file on this machine, and rendered into a bounded reply that is kept nowhere: the read performs nothing, reaches no provider, and is offered only for a local session whose provider's transcript this build documents reading (Antigravity, Claude Code, Codex, Gemini CLI, Grok Build, OpenCode, the Radius browser's own agent chats, and the Devin and Cursor agents running on this machine today); a cloud session's conversation lives with its provider and is never fetched. The read renders only what the provider actually wrote down (Cursor and Radius both keep tool outputs out of their transcripts, so those readings carry none, and Antigravity keeps tool outputs in blobs this build does not render, so an Antigravity reading carries the calls and never their answers) and a provider whose stored shape this build cannot render faithfully keeps the honest refusal instead.
  • Counting is three streams with three different guarantees, and the difference is the thing to keep straight. Only the first carries the guarantee, and the other two must never be described as though they borrowed it. The counted event stream may name only what the build already fixed: an event is a name from packages/analytics/src/product-events.ts and properties whose values come from as const sets in that same file, validated by one reader both the desktop and the service run and which builds its output from the allowlist rather than from what arrived. No observed value (a title, a branch, a path, a recap, a prompt, an error line) may reach a property, and no property may take free text; counts travel as buckets and versions as release versions. That guarantee is structural: there is no shape such a value could travel in. The desktop posts events to Luke's own service and never to an analytics provider, and the account is the bearer token's, so nothing identifying travels with them. The service attaches the account's own name and address to the analytics person record, read from its own user row, never from the request, and never onto an event, because an event property is what the allowlist governs and a person property is not. The renderer has one narrow way in — a fixed set of surface events the main process cannot see for itself — validated against that same allowlist in the main process before anything is queued, and reaching none of the acts. What the allowlist governs is that endpoint, /api/events, and not the analytics project: the two streams below reach the project without passing it, so a claim about the allowlist is a claim about Luke's own service alone.
  • The other two leave from the renderer, straight to the analytics provider, and both come from the one client in apps/desktop/src/renderer/session-replay.ts, configured as the library ships rather than hardened. The first of them is what that client captures beside a recording: an autocaptured event names the text of whatever was clicked, so pressing a session row sends that row's title, recap, and branch, and an unhandled error travels with its message and stack, which can carry a path or a title. Nothing validates either — no allowlist stands between the panel and the provider — and productEventFromWire never sees them. Both stop with the recording switch, because the client opts out rather than only stopping the recorder; a switch that named recording and left these running would be a consent nobody gave.
  • The replay stream has the opposite shape from the counted events. Except for the conversation History tab, it records the rendered panel, so everything drawn travels: a session's title, branch, recap, and error line, the account's own name and address, and any screenshot attached to the feedback composer, which is drawn as its own bytes and which input masking does not reach. The one thing withheld is what is typed into a field, and that is the library's default rather than a posture Luke keeps. The one explicit blocked subtree is History: its root carries the recording library's fixed blocking class, so the conversation's words do not leave the machine in a recording. That view retains every bounded line from the current renderer lifetime, including session acts, until the developer clears it or quits, while only the 20 most recent lines enter model context. There is no general masking module to consult and nothing that makes any other new component silent by construction, so what a recording may see is decided by what the panel draws or explicitly blocks — which makes drawing something new on the panel a decision about what leaves the machine. It is still Luke's own panel and never the machine's screen. Recording posts to the provider directly, and it begins at the first paint of every ordinary launch, before any account exists and through the spoken introduction, because the launch is where a first run goes wrong and a recording that waited for a sign-in never saw it. Recording is the one place an account id travels to the desktop, and it travels for what it does when a sign-in lands: the anonymous session already running is joined to that person, so it files with their counts and is erased with them. A session that never reaches a sign-in stays anonymous and can be erased with no account, which is a thing PRIVACY.md has to say in as many words rather than leave to be inferred. Deleting an account stands recording down for the rest of that run, unlike signing out, which leaves an anonymous recording running the way the launch before the sign-in was: nothing erased is re-created either way, but a recorder starting up again on the panel that just erased everything reads as though something were, and deletion is the one act treated here as unrecoverable. None of the three sends anything in a fixture or evidence run, and nothing else stands in front of any of them: there is no switch, and the run mode is the whole of the gate. That is the deliberate posture of an early product and it puts the entire weight of disclosure on PRIVACY.md, which is where a user learns any of this happens — so that file says all three in kind, in as many words, and moves whenever one of them changes character. Widening the event list, a property's value set, or what the recording client may capture is a product decision, not an implementation detail, and each one widens what a user was never offered a way to decline.
  • The development trace is the one place Luke's own agent traffic may reach a file, and it cannot exist for a user: only an unpackaged, live run whose shell set LUKE_TRACE_DIR constructs a writer at all, so a packaged build carries nothing to switch off and a fixture or evidence run stays silent behind the same gate that keeps it off the network. run.sh sets the variable by default, pointed at the gitignored build directory, so a development launch is traced unless --no-trace says otherwise — the launcher supplies the directory, and the app's own gate still decides whether anything is recorded. What it records is the desktop's own view of its own conversation — the realtime events already crossing the data channel, with an audio append reduced to its byte count before it leaves the renderer, and the attention evaluator's update, decision, and reviewing model when the desktop knows one — appended as JSONL under the developer's chosen directory and sent nowhere; pnpm trace:export turns one file into a document a local viewer opens. The tap only observes: nothing reads its result, and the main process drops the renderer's tapped events whenever no writer stands. A trace carries real titles, branches, and spoken words, so trace files are never committed, for the same reason fixtures stay synthetic. Widening what a trace records is a product decision, not an implementation detail.
  • The issue tracker follows the same rule at one remove, and is connected the way the calendar is rather than the way a cloud provider is. Luke reads the issues a tracker lists for the user under a grant the tracker's own consent page issued, and observes nothing without one. The integration exists only in a build carrying a registered OAuth client; without one it is not drawn. Connecting is the tracker's own flow for a public client: PKCE over a loopback redirect that never leaves the machine, carrying no client secret, asking for the narrowest scopes the acts need. No key is ever typed, and none is read from the environment: a tracker connected by consent has no environment variable at all. The grant is stored encrypted like a key, is renewed before it lapses (the renewal written before it is used, because a consumed refresh token is spent) and is deleted only when the tracker itself refuses the renewal, never when the network merely could not carry it. Disconnecting revokes the grant with the tracker as well as deleting it here. The two acts a tracker takes, moving an issue to a state its latest observation listed and adding a comment, happen only as the direct product of a turn the developer opened themselves, through the tracker's own documented endpoint under the same grant, validated against the observed issue roster in the renderer and again in the main process before the tracker client sees anything. Observation sends only the read document; the write documents are fixed by the build and issued only for a validated act.
  • The calendar is the same rule with no write path at all. Luke reads when the user's meetings start and end, under accounts the user signed in, and observes nothing without one. The integration exists only in a build carrying a registered OAuth client; without one it is not drawn. Connecting is Google's own consent flow for an installed app: PKCE over a loopback redirect that never leaves the machine, asking for two read scopes alone, availability and the calendar list. Each account's grant is stored encrypted like a key, deleted by disconnecting the account, and revocable in the user's own Google account; several accounts stand side by side. A pass reads each account's calendar list (ids and names, which are what the settings rows draw and the user chooses from) and then the Calendar API's free/busy query, a POSTed read document fixed by the build that carries the window's two instants and only calendar ids the same pass's list reported: the user's selection steers it, but never past what the account just offered. Google answers free/busy with intervals alone, so an event's title cannot even travel, and no event scope is ever held. Only start and end instants are kept beyond the pass, and the intervals never leave the machine. What the intervals decide is bounded and deterministic: while a meeting covers now and the setting is on, spoken announcements are held and released once it ends, and the face beside the housing sleeps for as long as the hold stands, a clock read against observed intervals, never anything a model wrote, and holding is the whole power: a calendar entry can delay an announcement and put a drawn face to sleep, never create, reword, or act on one. This Mac's own Calendar is read under the same rule with no credential at all, through a native helper behind macOS's own consent dialog. The dialog is the connection, and nothing is stored but the fact of it and the user's calendar choices. EventKit publishes no free/busy, so full calendar access is the grant the system asks for, and the helper is where the narrowing happens: an event is read for its start and end instants alone, and every other field (title, attendees, notes) dies inside the helper process, so intervals and the calendar list are all that ever reach Luke. The helper's commands are fixed by the build; nothing enters an invocation's arguments beyond the window's two instants and the calendar ids the user's stored choice names, intersected inside the helper with the list the same read produced; and a read never raises the dialog. A grant withdrawn in System Settings empties what Luke holds on the next pass, since nothing keeps standing on consent taken back, while a read that merely failed stands what it last showed, because a crashed helper says nothing about the user's intent. Disconnecting deletes the stored choice, and the grant stays the user's own in System Settings, withdrawable there like every system permission. The intervals pool with the signed-in accounts' and decide nothing more than theirs do.
  • Quieting other media is bounded the way the talk key is: a native helper that can do one narrow thing. While a spoken exchange is live, Luke may lower the volume of the players the helper names (Music and Spotify, through their own scripting interfaces, behind the system's per-app consent) and restore it afterwards. He never pauses them and reads nothing beyond whether each is playing and how loud; a volume the user moved during the duck stays where their hand put it; and the whole behavior is a setting. The trigger is the exchange itself, a deterministic status edge, never anything Luke read, heard, or decided, so no model output can reach it. Each player's consent dialog is raised at the last possible moment: macOS's standing answer is read before every event without a dialog, and a player never yet asked about is sent its first event — the one that raises the dialog — only mid-exchange, once the play-state broadcast that player already addresses to the whole machine says it is audibly playing. Those broadcasts are read for the one state word, and every other field (a track's name, its artist) dies inside the helper; the helper stands from the moment the setting is on so something is listening, but it writes the players nothing until a duck. The introduction reaches no duck at all — only a panel reports a spoken exchange, and the takeover is not one — so the dialog can never interrupt onboarding. Widening the player list is a product decision, not an implementation detail.
  • The same shape, smaller still, watches whether Luke can be heard at all: a native helper reads the default output device's mute switch and volume, nothing else, and can write nothing. What it learns decides only what the renderer draws while Luke speaks into that silence: his captions forced on, paced for reading rather than for the voice, because into a mute the caption is the speech, and a hint asking for volume. Luke never changes the system volume himself; turning it up stays the user's own act on their own keys.
  • The input side is read the same way: a native helper reports where the developer's voice would be captured from: the default input device's transport, whether the machine has a built-in microphone and what it is named, and whether the lid over it is open. Nothing else, and it can write nothing. No audio is ever read. What it learns decides exactly one act: which device the renderer asks the browser to open when a press takes a turn, so a Bluetooth headset is not pulled onto its call codec while the Mac's own microphone can listen, and is listened to itself when a shut lid would muffle the Mac's. The capture device itself stays bound to the turn the press opened, opened by the press and closed when the exchange settles, and never outlives it; typed asks never open one at all. An unreadable route means the browser's default device, never a refusal to listen.
  • Updating is the one thing Luke does on the network with no user-supplied key at all, and it follows the same shape Superset's production updater keeps: electron-updater reads this repository's release manifest from a feed address fixed by the build, an unauthenticated fetch carrying nothing about the user, their sessions, or their keys, on a timer of its own and at the press of the Updates row's button; never in a fixture or capture run, and never in an unpackaged build. A newer build found by any check downloads at once, so the row can offer a restart instead of a wait, but what is fetched is only ever what this repository's own release pipeline published: the manifest carries the archive's sha512, the archive must sit on the same release as the manifest, and Squirrel.Mac refuses one whose code signature does not match the running app's. The running build is replaced only at a quit (the row's restart press, or whenever the user next quits) and an install is asked for at most once, because repeat asks race the binary swap. The row's button is also a press that can be asked of Luke, only in a turn the developer opened themselves: the ask is validated in the renderer against the one act the row currently offers and lands on the same main-process guards the button's own press does, so it reaches nothing the button does not — the check, the restart, or the fixed releases page in the browser. A transient network failure is silence for the next timed check; a download refused just after its check found the version is a release still publishing, and the same check is retried at a few fixed delays against the same fixed feed — nothing new sent or read, only the cadence, and a network failure mid-wait spends the same bounded budget rather than orphaning it — with the row saying the wait honestly, before the schedule ends in the same error row a corrupt release deserves; any other failure is an answer on the row whose way forward is the browser, at the releases page fixed by the build, the same page that serves a build which cannot install in place at all. Widening what the updater sends, reads, or does is a product decision, not an implementation detail.
  • The spoken introduction is the one moment Luke runs before the account gate, and it is bounded on every side. It plays on the first interactive launch, before any account exists, at most once to the end: a completion on file never replays, and it never runs in a fixture or capture run. Its voice is the introduction mint, an accountless endpoint on Luke's own service that issues one short-lived credential per call, keeps nothing about the caller but a hashed network address for its own daily caps (per caller and global both), and answers the same pinned OpenAI calls endpoint every minted call uses. The call itself is tool-free at the API — no tools declared, every scripted turn opened with none — and no carrier is wired behind it, so nothing said, heard, or shown during the introduction can become an act. What travels on it is the build's own script and one observed thing: the detected sessions' titles, as data behind a marker, never as instructions, and capped at the panel's own visible depth however many sessions stand on screen. Detection is the keyless local peek — the same read-only observe every pass runs, once, with no hook registration and no credential, and answered only to the takeover window, which draws every fresh session it reports in a list that scrolls like the panel's own. The microphone is asked for at its own beat through the system's real dialog, the talk key is routed to the takeover for the introduction's duration, and the spoken sign-off is where the introduction ends: the takeover closes, the ordinary signed-out panel stands up with its own gate, and observation, announcements, and every other capability still release only through the ordinary account gate when the sign-in itself lands. An introduction that cannot speak stands down to the ordinary signed-out launch and writes nothing. Widening what the introduction reads, sends, or can do is a product decision, not an implementation detail.
  • Keep unsupported capabilities explicit; do not invent fallback controls.
  • Keep Electron renderers sandboxed with context isolation and narrow IPC.
  • Commit only synthetic fixtures and repository-relative paths. This binds harder as Luke observes more: a fixture copied from a real session now carries a real title, branch, and recap.

Read the full file on GitHub · 703 lines

Changes

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.

  1. 3d ago First seen · 703 lines · 11,029 tokens per session scan A 271290cc68cb

Subscribe to this mod's changes

luke AGENTS.md is an instructions file published in the GitHub repository ReviewStage/luke (24 stars, last pushed 4d ago), licensed Apache-2.0. It adds 11,029 tokens to every session, about $0.0551 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-30.

Related

Other instructions, from other repositories

vscode buildNext.instructions.md

Working notes and architecture documentation for the new esbuild-based build system in build/next. Use when making changes to the new build pipeline (transpile/bundle commands, NLS plugin, source-map handling, resource copying, or self-hosting watch tasks).

microsoft/vscode · 6,785 tokens

spec-kit AGENTS.md

AGENTS.md instructions for github/spec-kit, covering agents.md, about spec kit and specify, quickstart — add a new integration in 5 steps, integration architecture and integrationmanifest — file tracking.

github/spec-kit · 7,104 tokens

codex AGENTS.md

AGENTS.md instructions for openai/codex, covering rust/codex-rs, the codex-core crate, code review rules, crate api surface and model visible context.

openai/codex · 5,182 tokens

langchain AGENTS.md

AGENTS.md instructions for langchain-ai/langchain, covering global development guidelines for the langchain monorepo, corridor security analysis, project architecture and context, monorepo structure and development tools & commands.

langchain-ai/langchain · 4,345 tokens

vscode oss-third-party-notices.instructions.md

Instructions for microsoft/vscode, covering vs code oss third-party-notices pipeline, architecture, pipeline flow in ci, applying the notice (cutover) and fallback chain (never fail the build).

microsoft/vscode · 5,001 tokens

next.js AGENTS.md

Instructions for vercel/next.js, covering next.js development guide, codebase structure, monorepo overview, core package: packages/next and other important packages.

vercel/next.js · 7,296 tokens