Web app

The web app is served at https://app.usespotlight.ai, or at the deployment's address on a self-hosted Spotlight. Every page except /login and /invites/<token> is behind sign-in. Routes below are relative to the Spotlight address; <slug> is the workspace's slug and <teamId> a team's id.

The web app shows configuration read-only. Lines, stations, skills, integrations, hooks, harness profiles, secrets, pools and trusts are written through the resource API or the Terraform provider. There are two exceptions: the Add a host page creates pull pools, and the Tokens page issues and revokes workspace tokens.

The sidebar holds, from the top:

ItemLeads to
The workspace menu"Settings"; "Invite and manage members", which opens the Members page, for an owner or admin; the signed-in email, a switch between the person's workspaces, "Create or join a workspace" and "Log out".
"Inbox"The inbox, with the number of unread items.
"Your teams"Each team the person can see. A team opens to "Agent", "Lines" (one entry per line), "Runs", "Insights" and "Memory".

"Settings" in the workspace menu opens the settings area, which has a sidebar of its own. A red dot beside "Settings" means no host is answering.

ItemLeads to
"Back to app"The page the person left the app from, or the inbox.
"Workspace""General"; "Members", shown only to an owner or admin; "Runners", with the number of hosts answering; and "Tokens", shown only to an owner or admin.
Each team the person can see"General", "Integrations" and "Skills".

Pages outside a workspace

RoutePageShows and changes
/loginLog in"Continue with GitHub".
/workspaces/newCreate workspace"Log out" ("Logging out…" while it works) and "Logged in as:" with the email, above two steps. "Create workspace": a field with the placeholder "Workspace name", and the workspace URL after usespotlight.ai/w/, filled from the name until it is changed; "Continue" is turned off until both are filled. "Name your first team": a field with the placeholder "Product", then "Create workspace" ("Creating workspace…" while it works), or "Back". The fields' labels, "Workspace name", "Workspace URL" and "Team name", are read only by screen readers. See A workspace created in the web app.
/invites/<token>Accept an invite"<inviter> invited you to <workspace>", with the role and teams the invite gives ("You join as a member, on the <team> team."). Signed out: "Continue with GitHub", which returns to the page. Signed in with the invited address: "Accept invitation", which joins the workspace and opens its inbox. Signed in with another address: "Invitation is for <invited address>, not <signed-in address>. Please sign in as <invited address> to accept." A closed invite reads "Invitation already accepted.", "Invitation withdrawn." or "Invitation expired. Please ask for a new one."; a link that matches no invite reads "Invitation link doesn't work". See Invites.
/github/installedGitHub App callbackConnects the installation to the workspace. See Installation callback.

Workspace pages

RoutePageShowsCan change
/w/<slug>/inboxInboxThe person's conversations and notices, newest first, under "Open" and "Resolved".Nothing on the list itself.
/w/<slug>/inbox/notices/<noticeId>NoticeA notice: its headline, its points under "Details", and its link.Nothing. Opening it settles it.
/w/<slug>/inbox/<itemId>Inbox itemThe task's conversation: notes, the runs that worked it and their steps.Answer the conversation, with attachments. "Approve" or "Dismiss" an approval, edit a tool call's inputs before approving it, or copy the call. "Stop" a run still working the task. Grade a judged run (see Grades). "Approve" or "Reject" each memory a run proposed, editing its text before approving it. Read a station alert that went off (see Station alerts). Connect an integration a tool needs to act as you (see Requests to connect).
/w/<slug>/settings/runnersRunnersOne row per host serving the workspace and per push pool, under "Name", "Serves", "Status", "Images", "Harnesses", "Release" and "Last activity", filtered by "All", "Running", "Idle" or "Not answering". A host shows the pool or trust it came through, its standing ("Idle", "Running N of M" or "Not answering"), its default image with +N for the others and N refused for any it refused, the harnesses its images hold, its release, and Up since or Last seen. A push pool reads "Push pool", "Starting" or "Running N". Beneath each, one row per runner: the run it holds, or "No run yet", its standing ("Starting", "Running" or "Waiting on a person"), its image, its harnesses and when it started. A run of a team the viewer is not on shows a blurred title, with a tooltip saying it is hidden.An owner or admin opens "Add a host", or "Add the first host" while there is no host. A member reads "Only workspace owners and admins can add hosts."
/w/<slug>/settings/runners/newAdd a hostThree steps: "Create a pool", "Add the machine to the <key> pool" and "Wait for the host to connect". The last step waits until a host of the new pool connects; the page then opens Runners.An owner or admin creates a pull pool under "Pool name", which suggests my-computer-1 or the next free number, and "Create pool". The page then shows the install command with the pool's token in it, once, with "Copy command".
/w/<slug>/settings/membersMembersEveryone in the workspace under "Members": name, email, teams ("No team" for none) and role. Under "Pending invites", each open invite: address, teams, "Invited by" and "Expires in N days" or "Expires within a day", and the role it gives. "Filter members" narrows the page with "Show": "Everyone", "Owners", "Admins", "Members" or "Pending invites". Shown to owners and admins only; a member who opens the route is sent to the workspace's own route."Invite people" opens the invite dialog: "Email addresses" (separated by commas or new lines), "Invite as" ("Admin" or "Member", the default) and "Teams", then "Send invites". The dialog then lists each address with "Invited", "Sent again", "Already a member" or "Not sent. Please resend it from Pending invites.", under a title that counts each outcome, as in "2 invited · 1 sent again", from "invited", "sent again", "already in the workspace" and "not sent", or "Invites" with none. "Done" closes it. In a member's actions menu, "Change role". In an invite's actions menu, "Resend invite" and "Revoke invite".
/w/<slug>/settings/tokensTokensEach workspace token a person issued: its name, when it was created, "No expiry", "Expires" with the date, or "Expired", and its scopes. Never the token itself. A member who opens the route is sent to the workspace's own route.An owner or admin can "Create a token" with "Name", "What it is for", "What it may do" and "Expires after". "What it may do" is one of "Read", "Plan" or "Configure" (the default), with "Secrets", "Runners" and "Token trusts" beside it; "Expires after" is "30 days", "90 days" (the default), "1 year" or "Never". The page then shows the token, once, with "Copy token"; "I've copied it" dismisses it. "Revoke token" in a token's actions menu, then "Revoke token" again, revokes one.

See The inbox for what an inbox item holds and who may answer it.

Team pages

All team routes start with /w/<slug>/team/<teamId>, except a team's settings pages, which start with /w/<slug>/settings/team/<teamId>. The team's own route opens its first line, or "Runs" when it has none.

RoutePageShowsCan change
…/agentAgentThe person's chats with the team's agent, each with its harness, its title, a working indicator while the agent works, and when it last changed. With none, "No chats yet".Start a chat in the composer that reads "What do you want to plan?": pick the harness, model and effort, pick repositories, and attach files. Shared traces and a station to improve arrive in the composer only from the pages that open it with them, such as the Insights "Traces" tab and a station's "Improve" tab. See Chats.
…/agent/<chatId>ChatThe chat's messages, the agent's steps and answers, and the tasks it proposed, as cards (see Proposals). The first message names the station the chat improves, linked to it. While the agent works, "The agent is working…".Reply in the composer that reads "Reply…", with attachments, and change the model and effort for the reply. "Stop" the agent while it works. "Create task" or "Dismiss" a proposal, or copy it.
…/lines/<lineId>BoardThe line's stations as sections, with the tasks standing at each. The views "Backlog" (the backlog station), "Active" (work stations, the default) and "Completed" (the completed station). A task shows "Waiting for you" or that it is in progress.Create a task under "New task" (title, description, attachments, "Create more", "Create task"). Reorder tasks within a station by dragging. Start selected backlog tasks, or park selected tasks, with "Move to".
…/lines/<lineId>/stations/<stationId>StationThe station's name and description. A backlog or completed station shows only that nothing runs there. A work station has the tabs "Overview", the default, and "Improve"; another tab reads "Station not found". "Overview" shows "Latest runs on this config", over the config in force (see Station outcomes). Then "Config": "Agent", with the harness, model and effort, or "No agent" and Please pick a harness in Terraform.; "Prompt", or No prompt.; "Skills", with their count and names, or "None"; "Judge" (see Judge and alerts); "Ships through", with the line and its repositories; Alert rules · <n>, when the station has alerts; and "Version". Then "Runs": "Recent runs". "Version" and "Recent runs" read the newest group of runs with a recorded config, whether its runs started or not."See in Insights" and the version's "History" open the station on Insights (see One station), and the judge's "How it agrees with people" opens it at #judge. "All runs" opens the Insights Runs tab at the station. "View pull request" opens the pull request a picked search candidate opened for that version.
…/lines/<lineId>/stations/<stationId>/improveStation: ImproveFor a work station: "What stands out", with "Worth improving": the station's signals that got worse over the past 30 days or that trail the rest of the team, as under "Stations worth improving" on Insights. With none, it reads Every signal looks healthy over the past 30 days and There's always room to improve. Talk it through with the agent. Then "Try a change", with "Replay sets", at #replays (see Station page), and "Searches", at #searches (see Station page)."Ask the agent" beside a signal opens the Agent page with the station attached to a new chat and the message <signal> <now> (was <before>, all stations <all>). What should change at this station? written, leaving out a comparison it lacks. With no signal listed, "Review with the agent" opens it with the station attached. "Create a replay set" asks for a name, then opens the new set's page. "Start a search" starts a search over one of the station's sets.
…/lines/<lineId>/stations/<stationId>/replay-sets/<setId>Replay setUnder "Replays", the set's replays with their state, success, gain over the replay each one is compared with and spend; under "Health", its noise, room to improve, judge and checks readings; under "Runs", how its runs turned out, each run and whether it can still be replayed; under "Checks", the checks replayed on it. See Replay set page."Rename" or "Delete" the set. Turn "Guards config changes" on or off. "Add runs" from the station's latest ended runs, with runs suggested to even the mix, or take one out. "Start a replay" under a candidate or the live config, within a ceiling, replaying each run 1 to 5 times.
…/lines/<lineId>/stations/<stationId>/searches/<searchId>SearchA header with Search <n>, a pill for some endings, the replay set's name, linked, and when it ended, or started while it has not ended; tiles for the best candidate, the live config, iterations, tasks and spend; a Why it stalled (iteration <n>) card for each reflection; the "Candidates" card, each iteration's candidates with their scores, gains, cost and pull request, and a candidate's details beside it; and "Success against cost". See Search page."Stop" a search under way. "Pick" a candidate to open a pull request.
…/lines/<lineId>/stations/<stationId>/replays/<replayId>ReplayA header with the candidate's name, a "Stopped", "Over budget" or "Baseline" pill, the set's name, linked, from its search for a search's replay, and when it ended, or started while it has not ended; tiles for the replay's success and what scored it, its gain over the replay it is compared with, its side-by-side wins and what it spent; then "Tasks", each task's result against that replay, regressions first, and a task's runs, reasons, checks and changes beside it. See Replay page."Stop" a queued or running replay.
…/tasks/<taskId>TaskTitle, description ("No description" without one), attachments, and "Activity": every run of the task. A run that put the task to a person is led by "Waiting for you", or by "Answered" once the conversation is answered or closed, linked to its inbox item. Under "Properties": the station, the assignee, "Changes" when the task has a change stack, "View traces" when it has runs, and "Pull request" when it has one.Start, park or close the task with the station property. Assign it. "View traces" opens the task trace. "Delete task" from "Task options", then "Delete task" again, or "Keep it".
…/runsRunsThe team's runs, grouped by age, each with its task, its station, its state and when it started (see Run states). Filtered by "All" or "Waiting for you". With no runs, "No runs yet" and A run starts when a station picks up a task. Create a task to start one., with a link to create a task.Nothing.
…/runs/<runId>RunThe run's turn of the task's conversation: the task's notes from after the previous run's last note to this run's last note, or to the latest note while this run holds the task, with the run's steps as they happen and the files it changed. The briefing heads it, unless the turn opens with what a person said. While the turn holds no notes, the page shows Ran in <image> and the briefing, or the task's title and description. Once the run is not working, a toolbar: "Copy the conversation"; the "Remembered" icon, when the run was given or proposed memories, which opens a pane with "Given to the agent", the memories it was briefed with or recalled, and "Proposed by this run", each with its kind and handle, and a proposal with "Kept", "Kept, now retired", "Rejected" or "Waiting for you", which links to the inbox item while it waits there; and when the run last spoke. A run that waits on a person also shows "Waiting for you", with "Answer in the inbox", or "Open in the inbox" for an approval. A run that is not working, waiting or parked, whose turn holds no notes and no steps, reads The run failed before the agent started. or The run ended before the agent started., with "Open the task". The composer shows the station's harness, model and effort and the line's repositories, read-only (see Run page composer). A replay run or a search's agent run shows what it ran for in place of a conversation, and its composer is turned off (see Replay runs).Say something to the run, with attachments, answer its question, or send a finished station's work back to it. "Approve" or "Dismiss" an approval, edit a tool call's inputs before approving it, or copy the call; "Dismiss" first asks for a reason to tell the agent, which is optional (see Approvals). "Stop" a run a runner holds. In "Remembered", "This was wrong" on a standing memory asks why it no longer holds, then "Retire" retires it. Nothing on a replay run or a search's agent run.
…/runs/<runId>/changesChange stackThe run's change stack: cohorts, layers, each file's changes and notes, and the decisions on each file.Comment on files and lines, then "Finish review" with a summary and "Comment", "Approve" or "Request changes". The review posts to the task's pull request, or once the task opens one. Dispute a decision by replying to it.
…/tasks/<taskId>/traceTask traceOne task's trace on a time scale: a row for each run, <Station> or <Station> · attempt <n>, or "Run" for a run with no station, with the judge's score beside a judged run when it is shown (see Judge score); under it the phases "Prepare", Turn · <harness> and "Publish", and the run's steps and spans. Selecting a row shows its details: "Started", "Took", and, where they apply, "Status", "Tool", "Model", "Tokens", "Cost", "Rows" and "Faults"; a run's judge score; the step's "Input" and what came back; a file change's "Diff"; "Contents"; and "Attributes". With no runs, "No runs yet" and The trace fills in after a station works this task.Fold or unfold a row. "Open the task" when it has no runs.
…/memoryMemory"Filter memories" and "Write a memory" in the page header, then the team's memories in a table with the columns "Memory", "Kind", "Applies to", "Source", "Kept by" and "Runs", under the tabs "Standing" and "Retired" (?standing=retired). Standing memories are listed newest kept first, retired ones newest retired first, at most 500. "Filter memories" narrows them by "Kind", "Line", "Station", "Repository" and "Path", as the query parameters kind, lineId, stationId, repository and path. "Station" lists the chosen line's work stations, and is off until a line is chosen. "Repository" lists the chosen line's repositories, or those of every line. "Path" offers the paths of the memories listed, and matches every memory with a path that starts with the chosen one. "Kind" shows what the kind means on hover. "Applies to" reads "The whole team", or the line, station, repository and paths, or "Line deleted". "Source" reads "Person", "Run" or "Outside the team". "Kept by" names the person who approved or wrote it, or reads "Someone". "Runs" counts the runs briefed with it, that recalled it, or that read its file. Selecting a row expands it. In the "Source" column it then shows what the memory rests on: each note with a person's name, "A teammate" or "From another tool", and each step with the agent that ran it, or "The agent"; then "Open its run" and "Open its task". "Replaces:" gives the memory it replaced. A retired memory shows who retired it, when and why, or "A newer memory replaced this one." with "Replaced by:" and the newer memory. ?memory=<memoryId> expands that memory's row. With no standing memories and no filter, "No memories yet", Stations that keep memories propose them after runs. Approve them in the inbox, or write one yourself. and "Write a memory". With none to list otherwise, "No memories match.", or "No retired memories match." under "Retired"."Write a memory" (?write=1) adds a row at the top: the memory ("What the team should remember", at most 1,000 characters), "Kind" ("Preference" at first), "Line" ("The whole team"), "Station" ("Every station"), "Repository" ("Any repository") and "Paths, separated by commas", then "Save" or "Cancel". The row's "Source" reads "Person", "Kept by" your name, and "Runs" 0. On an expanded standing memory, "Edit" opens the same fields in the row. In both, "Station" is off until a line is chosen and the paths until a repository is, and choosing a line clears the station and repository. "Save" is off while the memory is empty and reads "Saving…" while it saves. Saving an edit keeps it as a new memory with a new handle and the source "Person", in place of the old one, which moves to "Retired". "Retire" asks "Why it no longer holds", at most 500 characters, then "Retire"; runs are no longer given it. In the memory and the reason, Cmd+Enter or Ctrl+Enter saves or retires, and Escape cancels.
…/insightsInsightsHow the team's runs, tasks and pull requests went over a period, against the period before, under "Overview", "Cost", "People", "Productivity", "Stations", "Tools and skills" and "Runs", and the team's task traces under "Traces" (?tab=traces). One station's figures, failures, runs by config and judge agreement at ?tab=stations&stationId=<stationId>. See Insights.The period. "Chart" or "Table" on a card that has both. On "Traces", select traces and "Discuss with the agent". "Improve" on a station worth improving opens the Agent page with the station attached. "Impact" on a config change, a diamond or a group of runs by config opens a side panel.
…/settings/generalGeneral"Team name", and "Members" with their roles.An owner or admin can "Add a member": choose someone under "In the workspace" who is not on the team, or "Invite someone new", which opens the invite dialog with the team ticked. Change a member's role.
…/settings/integrationsIntegrations"GitHub", then each integration the team defines, one row each. Selecting a row opens its details. Never a token. The GitHub row reads "Not installed on this team's repositories", "Works in this team's repositories" while its repositories load, or Reaches <n> repositories (Reaches 1 repository for one). A warning icon beside its name, labelled "Repositories not reached", shows when a repository the team's lines use is out of the App's reach; its hover reads The App can't reach <repositories>. Its details: "App", "Installed" or "Not installed", with Agents read code and open pull requests through it.; once installed, "Reaches", the repositories the App reaches, or "No repositories"; and, when the team's lines use repositories, "Lines use", each one out of reach with a "Not reached" warning icon whose hover reads The App can't reach <repository>. Agents can't work in it. Please give the App access on GitHub. An integration's row reads "Receives events" when it has no connection.oauth2, else "Acts as the team", or "Acts as each person" when its connection.holder is requester, followed by · <n> tools (· 1 tool for one) when it has an API description or MCP server read without a problem. A failed read shows a warning icon labelled "Could not be read", whose hover reads Its <OpenAPI description, GraphQL schema or MCP server> <problem>. Its details: "Team account", for an integration with connection.oauth2, with the account's handle, "Connected" or "Not connected", and Watches and posts for the team. for a requester integration, else Agents' tools act as this account.; "Your account", for a requester integration, with the person's own handle, "Connected" or "Not connected", and Its tools act as you on tasks you start.; "Acting as you", a rule for each tool, once the person is connected and the integration offers tools; "People", for a requester integration and only to owners and admins, who has connected, or "Nobody has connected yet", and Not connected: <names>; "Tools", <n> tools from its <OpenAPI description, GraphQL schema or MCP server>, read <when> (1 tool for one), where <when> is "just now", minutes or hours ago as in "5m ago", or the day after 24 hours, or the problem; and "Defined in", where the integration is defined.While a row is closed, its action shows on the row: "Install on GitHub" when GitHub is not installed; "Connect team account" to an owner or admin while the team account is not connected, and "Waiting for an admin" to anyone else; and "Connect your account" to a person not yet connected to a requester integration. In the details, "Install on GitHub" or "Manage on GitHub"; an owner or admin can "Connect team account", or "Change account" from the team account's actions menu; anyone can "Connect your account", or "Disconnect" from their account's actions menu, and set each tool's calls made with their connection to "Allow", "Ask me first" or "Block". While a connection opens, its button reads "Opening…". A failure reads Could not connect. Try again. or Could not disconnect. Try again. See Connect an integration that signs in with OAuth and Let a person ask first or block a tool.
…/settings/skillsSkillsThe team's skills.Nothing.

Only the task's assignee may answer, say something to a run or stop it. See Roles and permissions for who may invite, change roles and connect GitHub, and Change stacks and decisions for what a change stack holds.

Changed only through the resource API

WhatWhere it is written
Workspace name, team name, teams after the firstspotlight_workspace, spotlight_team
Lines, stations, prompts, reactions, review policyspotlight_line
Skillsspotlight_skill
Harness profilesspotlight_harness_profile
Integrations and hooksspotlight_integration, spotlight_hook
Secretsspotlight_secret
Runner pools, runner trusts, workspace runnersspotlight_runner_pool, spotlight_runner_trust, spotlight_workspace_runners
Workspace tokens and workspace token trustsWorkspace tokens, spotlight_workspace_token_trust

On this page