In VS Code

The ubCode extension surfaces the whole Pharaoh loop without leaving the editor: two dedicated Pharaoh panels in the sidebar, a Pharaoh Agent conversation panel for driving an ACP agent in place, workflow colouring and a gap overlay on the needs graph, and CodeLenses on every need. This page tours those surfaces.

Caution

The VS Code surfaces are the newest and most in-flux part of the feature. Panels, labels, and controls are still changing from release to release — treat the names below as a guide rather than a contract.

UI elements

The Pharaoh Workflows panel

In the ubCode activity-bar container, the Pharaoh Workflows panel is a vertical lineage graph of the need you are focused on: its ancestors above, the focused need in the middle, its descendants below. Each row is a need (not a stage), annotated with the workflow stage it belongs to and that stage’s state.

The Pharaoh Workflows panel showing a focused need's lineage, each row badged with its stage state

The Pharaoh Workflows panel: the focused need’s lineage, badged with stage states and gap chips.

A row shows:

  • a type icon, chosen per need type (and overridable with [workflow.icons]);

  • the need id and title;

  • a state badge done, ready, blocked, NEXT (the recommended next step), awaiting review, or stuck · <reason>;

  • a gap chip naming what the need is missing (for example no test).

When the recommended next step is a need that does not exist yet, a ghost row with a to create badge marks where it will go.

Its controls:

Depth

A directional selector — Parents · N and Children · N — with / + to show fewer or more levels in the active direction and Max for the full lineage. The depth is sticky as you move focus.

Expand / collapse gutter

When a lineage has more parallel rails than fit, a toggle switches between Graph clipped to fit and a scrollable expanded view.

Capture intent / Tailor workflow

Buttons for the same-named commands (see Commands). A small Copy intent prompt icon beside Capture intent copies the intent authoring prompt for any agent to paste.

Search and back

A Search a need to focus… box, and a ← Active work button that returns the panel to the git-derived list of what you are working on right now.

Per-row actions

Every row with a next stage carries a Copy drive prompt icon, always shown, that puts the drive prompt on the clipboard for any agent. Next to it, when your agent is one ubCode integrates, a Drive button hands the step straight to it: ▶ Drive prefills Copilot Chat, and a Drive in Pharaoh panel icon sends the prompt to the Pharaoh Agent panel over ACP. Which one appears follows ubcode.agent.id (see Settings).

Title bar

Refresh re-indexes and redraws; Help toggles an in-panel help sheet.

When nothing is focused, the panel shows Active work — the stream derived from your uncommitted changes (ubc agent next with no anchor).

The Pharaoh Gaps Overview panel

Its sibling, the Pharaoh Gaps Overview panel, is a project-wide census — never scoped to the focused need. A header reads <N> needs · <M> gaps, and a By need / By type toggle switches between one row per gapped need (with a chip for each missing artefact) and one section per missing type (Missing test, and so on).

The Pharaoh Gaps Overview panel listing gapped needs with a chip per missing artefact

The Pharaoh Gaps Overview panel: the project-wide census of open gaps.

On a fresh project it doubles as an on-ramp: it offers Set up project (ubc agent install) when there is no configuration, and Capture intent / Tailor workflow when there are no needs yet.

The Pharaoh Agent panel

When ubcode.agent.id is an ACP agent (claude-code, mistral-vibe, or opencode), the Drive action does not open a terminal or a foreign chat window. It sends the prompt to the Pharaoh Agent panel, ubCode’s own conversation view. The panel sits at the top of the ubCode activity-bar container, above Pharaoh Workflows and Pharaoh Gaps, and holds one running ACP session. It starts collapsed (for the default GitHub Copilot agent it is inactive, so it does not take the space), and Drive or Capture intent reveal it on use. Click its header to open it for manual chat. Pharaoh Workflows is the expanded panel the container opens on.

It works the same whichever ACP agent you pick, because both speak the Agent Client Protocol. In the panel you see the agent’s replies stream in, and when the agent wants to run a tool or touch a file it asks inline, so you answer each request as it comes and a driven step never edits your project behind your back. The buttons on a request are the agent’s own: usually allow and reject, but an agent may offer more (Claude Code asks how to leave plan mode with three), and the panel shows each one under the label the agent gave it. A tool call is a collapsed line you can expand to see what was run and what came back. You can also type directly into the panel to continue the conversation.

An agent picker in the panel toolbar chooses who you talk to without editing settings. Claude Code and Mistral Vibe drive the panel over ACP (it repoints ubcode.agent.id and restarts the session). GitHub Copilot switches ubcode.agent.id to Copilot and leaves the panel inactive, since Copilot runs in the native Copilot Chat, not here.

A blank conversation offers ready-made Capture intent and Drive next step prompts as one-click buttons (or Onboard Pharaoh when the project has no workflow yet). New session clears the conversation after an inline confirm, and Auto-approve allows tool permissions for the session without a card each time (allow-once each, nothing saved to disk).

Both ACP agents need an API key, which the panel reads from the environment VS Code was launched from (it never stores keys).

Mistral Vibe needs MISTRAL_API_KEY (or a key in vibe’s own config) set there before you pick it. Without it the first turn fails with a missing-key error.

Claude Code over ACP needs ANTHROPIC_API_KEY, an Anthropic Console API key, not a Claude subscription login. Anthropic does not permit subscription (Pro, Max) OAuth credentials in third-party clients or the Agent SDK (legal docs), so the panel checks for the key before spawning and refuses to start Claude Code without it, rather than silently falling back to a logged-in subscription session. To use a Claude subscription, run Claude Code natively instead.

How the ACP panel works

The panel speaks the Agent Client Protocol (ACP), the same protocol Zed uses to host external agents. Useful things to know when working with it:

Where the agent runs

The agent is a separate process the panel launches (chosen by ubcode.agent.id), talking JSON-RPC over stdin/stdout. It runs in your workspace with the project’s installed skills available, so it can read and edit files and run commands the same way it would in its own CLI. The panel is the client: it shows the conversation and relays your input, it does not run the tools itself.

Documentation grounding

The panel’s agent can search and read the official sphinx-needs and ubCode documentation through two MCP tools, search_docs and fetch_doc_page, so it grounds product and how-to answers on the real docs rather than guessing. The @pharaoh Copilot participant grounds on the same documentation engine, reached through the language server instead. Either way the pages are fetched from the public documentation sites over the network, and no project data is involved.

Skills, per agent

ACP has no standard channel for handing skills to an agent, so each reads them its own way. Claude Code auto-discovers .claude/skills, where ubc agent install writes them. Mistral Vibe and OpenCode read the harness-neutral .agents/skills location, which ubc agent install also writes, so they see the same skills as Claude Code. For Vibe the panel grants the workspace trust when it launches it (Vibe loads no project-local config, skills or AGENTS.md, until the folder is trusted).

Tools and what you see

When the agent runs a tool (reads a file, runs a command, edits a need), the panel shows it as a row you can expand to see the input and the result. The agent decides what to run; the panel reflects it. An agent that acts without asking (some models are eager) will not raise a permission request, so the row is your record of what happened.

Answering the agent

For an open-ended question the agent just writes it and you type your answer as the next message. For a decision it needs gated, it sends a permission request, which the panel renders as a card with the agent’s own options as buttons. ACP has no separate “ask the user a multiple-choice question” call, so agents use permission requests for that too: leaving plan mode in Claude Code, for instance, offers three buttons. Always allow (when an agent offers it) means the agent may stop asking for that kind of action for the rest of the session, so read the label before clicking it. Auto-approve answers the plain allow-once option for you and never the always variant.

Sessions

One conversation is one ACP session, held for the life of the panel. A Drive action starts a fresh session each time, since a driven step is a self-contained task and should not inherit an earlier conversation’s context. Your own chat in the panel continues its session, so follow-up questions keep their context. New session clears the current conversation by hand (it cannot be undone today, and restoring a previous conversation is tracked separately). Moving the panel to another location keeps the session and its transcript.

The needs graph

The needs graph view gains workflow awareness: nodes are coloured by need type, the trace links between them are drawn as labelled edges, and a need still missing a required link carries a red marker naming that link.

The needs graph with type-coloured nodes, labelled trace edges, and a red marker on a need missing a required link

The needs graph: nodes coloured by type, trace links as labelled edges, and a red marker flagging a need that is missing a required link.

Click any node to make it the focus, which also updates the Pharaoh panels.

The workflow editor and flow views

Two more webviews visualise the process itself:

  • Open Workflow Editor draws your [workflow] as a V of stages — each a node coloured by the type it produces, edges labelled leads_to, optional stages dashed and tagged [optional]. Selecting a stage shows its Produces type, its Authoring directive, its hard-gate and soft-review chips, and where it lives in ubproject.toml.

  • Open Flow shows the V-model stream for the currently focused need.

The workflow editor drawing the configured stages as a V, with one stage selected

The workflow editor: your [workflow] drawn as a V of stages, with the selected stage’s details.

Quality analysis (Run QA)

The review and quality gate has an in-editor front end. Run Quality Analysis (the ubcode.need.runQA command — command palette, the editor right-click menu, or Ctrl+Alt+Q / Cmd+Alt+Q — with a need under the cursor) scores that need against its criteria pack using the editor’s own language model. ubCode never calls a model provider itself; the first run asks which model to use, and you can pin it with the ubcode.qualityAnalysis.llmselection setting.

The result opens in the ubCode Quality Analysis panel (the Show Quality Analysis Results command, ubcode.need.qaResults): one row per axis with its score, the reviewer’s reason and suggestion, any floor breach highlighted, and a freshness banner when the verdict no longer matches the need or its rubric. Inline, a QA CodeLens shows a reviewed need’s verdict state and score at a glance.

Both surfaces refresh live: a verdict is just a file under .pharaoh/verdicts/, so a verdict written out of band — by the drive loop, or by ubc agent verdict-submit on the command line — updates the panel and the lenses automatically.

Run QA follows ubcode.agent.id too, so the agent you pick for Drive also scores QA. Pick an ACP harness (claude-code, mistral-vibe, opencode) and Run QA scores each axis through it, on its own model and key, instead of Copilot. Since ubcode.agent.id defaults to copilot, Run QA stays on Copilot unless you pick an ACP agent. Because an ACP agent scores on its own model and API key, choosing (say) claude-code for Drive also routes Run QA through that agent’s key rather than the Copilot model. To score with a different agent than you drive with, set ubcode.qualityAnalysis.agentId (for example copilot to keep QA on Copilot while driving with an ACP agent). Using a different agent for QA than for authoring avoids the self-review bias a single model has when it scores its own work, and scoring quality tracks the model you choose. Absolute scoring accuracy against a labeled corpus is unmeasured for any agent, Copilot included.

The ubCode Quality Analysis panel showing per-axis scores with reasons and suggestions, one axis below its required floor and failing the gate

The ubCode Quality Analysis panel: per-axis scores with the reviewer’s reasons and suggestions, and a below-floor axis highlighted as failing the gate.

Commands

All of the following live under the ubCode category in the command palette (Ctrl+Shift+P):

Focus Need in Pharaoh Panel

Reveal the Pharaoh Workflows panel and focus the selected need. (Also reachable from the Focus CodeLens, and — from a need in an RST file — via the editor right-click entry Show ubcode need ID in the Pharaoh panel.)

Drive Next Step

Hand the focused need’s next step to your agent. How it is delivered follows ubcode.agent.id (see Settings): Copilot Chat is prefilled, an ACP agent receives the prompt in the Pharaoh Agent panel, or the prompt is copied to the clipboard. Nothing runs until you send it.

Change Request

Send your agent a change-request prompt to propagate an edit downstream through the V (the change-request cascade). Delivered the same three ways as Drive Next Step.

Accept Authored Artefacts

Stage and commit the artefacts the assistant authored, with an attribution message.

Capture intent (/pharaoh-intent)

Capture a high-level intent as the root artefacts your workflow defines. It follows the same three routes as Drive: Copilot Chat opens prefilled with @pharaoh /pharaoh-intent, an ACP agent gets the authoring prompt driven into the Pharaoh Agent panel, and any other agent gets it on the clipboard. All three build the same prompt (root artefact type, routed path, id convention) from the workflow and the engine brief. A Copy intent prompt icon beside the panel’s Capture intent button copies that prompt on demand, whatever ubcode.agent.id is set to.

Tailor workflow

Derive a proposed [workflow] from the project’s need types and links, preview the TOML, and write it into ubproject.toml (with an option to refine it in chat).

Install agent skills

Run ubc agent install in a terminal to scaffold the profile’s skills into the project.

Run Quality Analysis / Show Quality Analysis Results

Score the need under the cursor against its criteria pack (using the editor’s model), and open the results panel. See Quality analysis (Run QA).

ubCode: Open Flow / ubCode: Open Workflow Editor

Open the two process webviews described above.

Settings

These settings tune how the agent commands behave:

ubcode.agent.id

Which agent the Drive Next Step and Change Request actions dispatch to. The value picks one of three delivery routes:

  • copilot (default) prefills GitHub Copilot Chat in the editor, the one native integration. It falls back to the clipboard if the Copilot command is absent.

  • claude-code, mistral-vibe, and opencode drive the Pharaoh Agent panel over ACP (the Agent Client Protocol). All are ACP agents, with no terminal path. Pick one from the panel’s agent selector.

  • other copies the drive prompt to the clipboard so you can paste it into any agent ubCode does not integrate.

ubcode.agent.cliPath

The path to the ubc binary the need-level agent commands invoke (default ubc).

ubcode.qualityAnalysis.llmselection

The Copilot model Run QA uses to score needs. Leave empty to be prompted on first use.

ubcode.qualityAnalysis.agentId

The agent Run QA scores with. Empty (default) follows ubcode.agent.id, so the agent you drive with also scores QA. Set it to pin QA to a specific agent, e.g. copilot to keep scoring on the Copilot model while driving with an ACP agent. Using a different agent for QA than for authoring avoids self-review bias, and scoring quality tracks the model you choose.

Gap diagnostics

Gaps also appear in the Problems panel, and as squiggles on the need’s directive line: a warning <id>: gap in <category> for a structural gap, and an information <id>: needs clarification for a clarification marker. The gap CodeLens jumps straight here.

CodeLens elements

On needs in .rst and Markdown files, ubCode renders a row of CodeLenses just above the directive — which lenses appear depends on the need. Each is one click:

Focus

Focus this need in the Pharaoh panel (the same action as the Focus Need command). Shown on every workflow-scope need — any need whose type the [workflow] covers (a type a stage produces, or the up target of a stage’s trace edge) — so you can jump into the lineage from a req or arch in the middle of the chain, not just from a feature root. A need whose type the workflow never references (a plain note, say) gets no Focus lens; the Focus Need command still works for any need.

Parents

Shown as N parent(s); jumps to the parent need’s source (a picker when there is more than one, and the parent’s id in the hover tooltip when there is exactly one).

Children

The mirror of Parents — shown as N child(ren), jumping down to a child need.

Code trace

Shown as N impl · M tests; opens the source file(s) the need’s codelinks point to. Omitted when the need links to no code.

Gap

Shown only when the need has a gap — the reason(s), such as no test, no impl, or clarify for a clarification marker. Clicking it opens the Problems panel.

QA

Shown on a reviewed need with its verdict state and score. Clicking it opens the ubCode Quality Analysis panel for the need. See Quality analysis (Run QA).

A need directive in the editor with its CodeLens row above it

The CodeLens row above a need: navigation and gaps, one click away.

Note

The CodeLens row is on by default. Disable it project-wide with the code_lenses key in the [server] section of ubproject.toml (see server configuration) to remove the lens line above every need.

See also