Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ curl -fsSL https://raw.githubusercontent.com/AgentSystemLabs/agent-office/main/i

## What it is

- **Opora process wall.** Above the north-wall boards, aim and press E for a live view of workers, queue tasks, branches, GitHub checks and blockers. Switch views, inspect observations, query actual OpenViking role memories through Opora (`OPORA_CONTROL_CENTER_URL`), or open the detailed demo inside the same window. See [connection setup, controls and data boundaries](docs/process-wall.md).
- **Process Observatory (interactive demo).** Open `/process-studio` after signing in to explore a Czech-language simulation of an Opora plan, parallel office workers, failed checks and repair, GitHub delivery, and memory reuse. A six-phase delivery pipeline exposes 17 handoffs, from source investigation and worktrees through counterexamples, review, PR dependencies, staging and evaluation. Animated agents follow recorded events; repository-role inputs extend the local scenario. It uses sample data and does not connect accounts or change repositories. See [the scenario, controls and integration boundary](docs/process-studio.md).
- **A floor per project.** Ride the elevator, pick one of your GitHub repos, and the office clones it (showing how far along it is) and opens a floor for it. Every worker, board and queue on that floor works in that checkout.
- **Workers at desks.** Walk up to an empty desk, press **E**, and pick Claude Code, Codex, OpenCode, Grok, Muse, DeepSeek Harness, Pi or Cursor, each with its model and reasoning effort. The agent's live terminal shows on its laptop, and anyone can open it and type.
- **Talk instead of typing.** Hold **Ctrl+Space** (or the **🎤**) in a worker's terminal or a prompt box and say what you want: it's typed in for you to send. Your browser does the listening, so there's nothing to install.
Expand Down
72 changes: 72 additions & 0 deletions docs/process-studio.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Process Observatory

The separate `/process-studio` page is an interactive Czech-language **simulation**, built with the office and protected by its existing session authentication. After signing in, navigate to `/process-studio`. With the Vite development server, open `/process-studio.html` instead. No additional dependency or server configuration is required.

It demonstrates how an Opora task, office workers, memory and GitHub could share an observable workflow. It does not connect to Canvas, OpenViking, GitHub or a running worker. Every event, test result, memory record, PR and merge displayed on the page is model data.

The [office process wall](process-wall.md) embeds this demo alongside its separately labeled live views. Only this session-authenticated page allows same-origin framing (`X-Frame-Options: SAMEORIGIN` and CSP `frame-ancestors 'self'`). Other static pages retain denied framing.

## What the scenario demonstrates

1. A card has a goal, scope, expected output and acceptance conditions. Recall brings earlier experiences into the plan.
2. A missing reconnect condition blocks handoff. Refinement creates a new revision, with explicit proof requirements.
3. Two workers perform parallel work in the modeled office. Their completion is distinct from passing checks.
4. A duplicate-event regression fails a check. The workflow grows a repair node and a new plan revision. Earlier checks and approvals become invalid.
5. New checks cover the repaired behavior and every added repository. Review and a sample PR become available only for the current revision.
6. The simulation stops at the human decision. **Schválit v ukázce** authorizes only the local scenario to continue; it does not merge a real PR.
7. A memory candidate is proposed from the evidenced result, then a separate event confirms persistence. A subsequent task recalls it. Reuse is not presented as measured improvement.

The precise acceptance conditions and evidence are available under **Plán** and **Detail**. The spider animation only interpolates positions from state; it never controls a transition or supplies evidence.

## Controls

### Delivery pipeline

The six-lane pipeline below the graph exposes 17 ordered handoffs. Select a step to inspect its owner, input, output and handoff condition; **Sledovat další předání** restores automatic selection. Its progress and selected-step status derive from the same snapshot as the graph, including history replay. The next highlighted handoff is pending, not a claim that a tool is currently running.

| Phase | Intermediate work |
| --- | --- |
| Opora | Intake and risks; source provenance and repository instructions; acceptance contract and state model |
| Office | Fresh main and baseline results; isolated worktrees and file ownership; minimal counterexample and regression test |
| Evidence | Integration of worker changes; model-to-code correspondence; independent review; simplification decision |
| GitHub | Documentation and PR package; CI for the current head and dependency ordering; human approval and merge queue |
| Delivery | Versioned artifact; staging smoke checks and rollback plan; evidence-linked task closure |
| Memory | Recall, propose, persist, reuse and a separate plan for paired evaluation |

This adapts the supplied verification/review/PR video into the office workflow, without copying its numeric results. The video inspires counterexample-driven repair, independent implementation review, simplification, dependent PRs and a final evidence summary. The demo does **not** execute Lean, prove a program, open multiple real PRs, run CI or deploy. Its dependency strip is a proposed contract → UI → extension ordering; only sample PR #214 receives a modeled merge. Production rollout remains a separate decision outside the scenario.

The simplification step explicitly makes no code change in this run. A real follow-up diff would invalidate checks and review for the previous SHA and require another cycle. The existing repair loop shows failure → revised plan → repair → new checks. Merge, staging verification, task closure and memory writing are distinct handoffs; they cannot be skipped in the modeled run. Evaluation is only a plan, with no claimed improvement percentage.

### Playback and inspection

- **Tok procesu / Vazby paměti** switches between the workflow and an illustrative context/evidence relationship view. The latter does not depict an LLM's internal neurons.
- **Pozastavit**, **Krok**, speed and restart control the deterministic scenario. Reduced-motion preference starts it paused and suppresses procedural motion.
- Select a node with a pointer or Enter/Space to inspect its status, revision and evidence.
- The history slider restores an earlier snapshot for viewing. It pauses playback and hides the approval action. Returning to the latest event does not automatically resume playback.
- **Exportovat stopu** downloads JSON with `schemaVersion`, `mode: "simulation"`, the run, configured repositories and observed events. The application does not import arbitrary event files.
- The information dialog closes with its top-right X or Escape and restores focus to its opener. This standalone page has no 3D player or mouse-look to restore.

## Adding a repository to the model

The **Moduly** pane opens by default. Supply an exact `https://github.com/owner/repository` URL and choose a role: context source, implementation module or checking service. Up to four additional repositories can participate.

Adding one starts a new model run and clears that run's previous history. Export first if the previous trace is needed. The extension receives a visible graph node, an inspect/verify step, a plan entry and a mandatory inclusion in the subsequent checks. It is kept only in page memory; reloading clears it. Duplicate identities and malformed URLs are rejected. URL values are rendered as text, not HTML, and are never fetched or cloned.

This describes how an integration contract could appear. It does not infer an unfamiliar repository's architecture or execute any of its functions. A functioning integration still needs an authenticated adapter and independently verified input/output semantics.

## Implementation and future integration boundary

- `src/client/process-studio/model.ts`: pure state reducer, event identity/order, plan revisions and evidence gates.
- `scenario.ts`: the explicitly simulated producer; repository extensions insert their steps here.
- `pipeline-model.ts`: ordered handoff registry and prerequisites; `pipeline.ts` / `pipeline.css`: accessible six-lane projection and contract inspector.
- `graph.ts` / `motion.ts`: graph projection and separate visual interpolation.
- `panels.ts` / `index.ts`: inspection, playback, history, extension form and trace export.
- The Vite input registry and `http/routes/index.ts` register this entry independently of the 3D office and its state store.

Future live adapters need to correlate `run`, task, worker, repository, plan revision, operation/attempt and evidence identity. They must translate actual service observations into domain events, authenticate the source, handle reconnect snapshots and persist events. The demo reducer is **not** an authorization boundary or a production ingestion API: it consumes a local typed scenario, not untrusted service messages.

In particular, OpenViking session submission is not confirmation that asynchronous memory processing finished. Recall only proves that context was supplied, not that it caused a better answer. A claim of improvement requires a comparable evaluation, outside this demonstration.

## Verification

Run `npm run typecheck`, `npm test`, and `npm run build`. `tests/process-studio.test.ts` checks the complete scenario and failure paths: missing plan conditions, invalid/stale evidence, blocked merge, duplicate/out-of-order observations, missing repository coverage and memory lifecycle ordering. Use a headless browser to exercise the actual page, including the repository form, replay and human gate, and capture both graph views.
39 changes: 39 additions & 0 deletions docs/process-wall.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Opora process wall

The 3D office has a wide, illuminated **OPORA · Řízení práce** display above the north-wall Issues, Task queue and Pull Requests boards. Aim at it and press **E** or click to open its readable detail window. The wall occupies the upper wall above the existing board labels; it does not replace the task boards or obstruct the floor.

## Views and controls

- **Celý proces** joins queue tasks, workers and PRs using worker identities, PR numbers and branch names. Three prioritized rows fit the physical screen; **Další strana na stěně** cycles additional rows.
- **Pracovníci** filters to rows with an observed worker. **Blokace** shows requests for input, lost worktrees, failed tasks, failed GitHub checks and requested review changes. Selecting these views also changes the physical wall, locally for that viewer.
- The window shows each row's branch, observed phase, head SHA when supplied, checks, review and a GitHub link to inspect the PR evidence. Its phase marker is a projection, not a completed-step checklist.
- **Historie pozorování** keeps the latest 80 changed row observations in browser memory. It clears on a fresh welcome/floor snapshot and page reload. It is not a durable or complete server audit.
- **OpenViking · živě** reads the real memory status and role registry through Opora. Choose a role and a query to recall existing memories, with source URI, origin and retrieval score. An optional project field takes an exact Opora project ID; an office branch/repository name is never silently treated as that identity.
- **Podrobný plán · DEMO** embeds the existing [Process Observatory](process-studio.md), including the six-phase pipeline, repository-role form, memory proposal/reuse and replay. It is clearly separated from live office data.
- The top-right **✕** and **Esc** close the window using the office's normal modal/focus lifecycle. Escape also works from the embedded demo; if that demo's own information dialog is open, the first Escape closes that inner dialog.

The small animated spider on each row stays at the observed phase. Its legs move only when the worker reports `working`, the socket is connected and the current snapshot is ready. Reduced-motion preferences suppress that motion. There is no invented automatic advancement when the office is idle, and the wall never launches work or changes a PR.

## Live data and limits

The wall reuses the existing authenticated office connection and store, without another socket or credentials. Worker updates, queue updates and GitHub PR snapshots refresh its projection. Disconnects show **ODPOJENO** and freeze motion; reconnects show **SYNCHRONIZACE** until the floor snapshot arrives. The detail displays the last relevant observation time separately from GitHub's fetch time and errors. GitHub snapshots older than three minutes are flagged as potentially stale.

A worker's `done` means its turn ended, not that tests passed. A test tool call means a check was invoked, not that it succeeded. Passing CI and an approved review still do not mean merged. Only the PR snapshot's `MERGED` state produces the merged phase, and it does not imply deployment.

Opora's external plan, releases and deployment do not yet have live event adapters. Their proposed contracts remain in the clearly labeled demo. OpenViking now has real status and recall through the existing Opora API, but no memory-write or learning-event stream. The live view does not claim complete coverage of background mechanisms or provide elapsed-time comparisons across runs. Durable correlated events are required for those capabilities.

## Connecting the existing Opora/OpenViking service

Set `OPORA_CONTROL_CENTER_URL=http://127.0.0.1:8740` in the **agent-office server** environment, then start/restart that server. Use your actual Opora port if different. Without this explicit setting the adapter is disabled. The URL must be an HTTP loopback origin without credentials, path, query or fragment. Opora keeps its existing OpenViking address, enablement and role keys; agent-office never reads or returns those keys.

The authenticated `/api/process-memory` and `/api/process-memory/recall` endpoints permit only administrator accounts or the office's shared-password session. This matters because Opora's role memories span projects. Recall also requires the office's Origin header. The server calls only Opora's fixed status, roles and recall endpoints, without redirects or proxies, with response-size bounds and deadlines. Returned fields are explicitly selected. No provisioning, settings, writes or session commits are forwarded.

Status refreshes every 15 seconds while the memory tab is open; leaving it cancels browser requests and polling. Recall runs only when submitted. Results are rendered as text, not instructions or HTML, and remain labeled with the submitted role/query/project. `configured` means Opora reports its memory service configured, not that every lookup succeeds. A recall failure is shown separately. Retrieval scores are not measures of agent quality.

OpenViking must be running independently (the local setup uses Docker and Ollama). If the service is down, Opora's `unavailable` state is shown. Start the existing OpenViking deployment and verify Opora's `/api/memory/status`; do not create replacement role keys merely to make the visualization green.

## Implementation and validation

`src/client/features/process-wall/` owns the pure projection/history model, canvas texture, fixture, modal and subscription lifecycle. The feature joins the main install list and office fixture registry; no global store or protocol additions are needed. It is available on the office map, not on alternate castle/station maps or `/lite`.

Run `npm run typecheck`, `npm test`, and `npm run build`. `tests/process-wall.test.ts` verifies association, blockers, status/evidence distinctions, stale connection labels and bounded history. Visual verification should cover the real 3D fixture, live projection with controlled worker messages, view switching, nested demo Escape, mouse-look restoration, disconnect and mobile detail. Synthetic test messages are browser fixtures, not claims of real agent execution.
47 changes: 47 additions & 0 deletions src/client/features/process-wall/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type * as THREE from 'three';
import type { Ctx } from '../../core/context';
import { hintTitle, key, onE } from '../../core/hint';
import { store } from '../../state';
import { projectWall, WallHistory, type WallView } from './model';
import { ProcessTexture } from './texture';
import { ProcessWallPanel } from './ui';

declare module '../../world/types' {
interface InteractKinds {
processwall: true;
}
}

export function installProcessWall(ctx: Ctx) {
const texture = new ProcessTexture(), history = new WallHistory();
const mat = ctx.office.processWall.screen.material as THREE.MeshBasicMaterial;
mat.map = texture.texture; mat.needsUpdate = true;
let view: WallView = 'overview', page = 0, ready = false, at = 0, lastDraw = 0, lastPanel = 0;
const snapshot = () => projectWall({
floor: store.currentFloor()?.name || 'Čeká na patro', workers: [...store.workers.values()], tasks: store.queue.tasks,
pulls: store.pulls, connected: ctx.net.up, ready, at,
});
let current = snapshot();
let memoryLabel = 'ověřit v detailu';
const panel = new ProcessWallPanel(history, next => { view = next; page = 0; lastDraw = 0; }, () => { page++; lastDraw = 0; }, label => { memoryLabel = label; lastDraw = 0; });
const refresh = () => { current = snapshot(); panel.update(current); lastDraw = 0; };
ctx.interactions.define('processwall', {
reach: 18,
hint: () => ({ k: 'process-wall', parts: [hintTitle('OPORA · Řízení práce'), key('E', 'Sledovat proces')] }),
use: onE(() => panel.open(current)),
});
ctx.net.onStatus(() => { ready = false; refresh(); });
ctx.messages.onAny(message => {
if (message.t === 'welcome' || message.t === 'floor.enter') { ready = true; history.clear(); page = 0; }
if (!['welcome', 'floor.enter', 'worker.update', 'worker.remove', 'worker.worktree', 'queue', 'gh.pulls'].includes(message.t)) return;
at = Date.now(); refresh(); history.observe(current); panel.update(current);
});
ctx.ticks.add('world', frame => {
if (document.hidden) return;
if (frame.now - lastPanel > 1000) { current = snapshot(); panel.update(current); lastPanel = frame.now; }
if (!ctx.inOffice() || ctx.upTop()) return;
if (frame.now - lastDraw < (current.running && current.connected && ready && !ctx.reduceMotion.matches ? 100 : 1000)) return;
texture.draw(current, view, page, frame.t, ctx.reduceMotion.matches, memoryLabel); lastDraw = frame.now;
});
texture.draw(current, view, page, 0, true);
}
Loading