tiann / tiann/hapi

RFC: Import external agent sessions + hub-scoped operator context

Open
#732 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

area:hub area:web status:pr-open type:rfc
Dominant language
TypeScript
Stars
5.1k
Forks
570
Avg merge
3d 11h
Merged PRs (30d)
61

Description

Summary

HAPI works well when a session is born inside HAPI. It is awkward when work started in a native agent surface (Cursor IDE, Claude Code CLI, Codex CLI, etc.) needs to continue from the web/PWA or remote runner.

Today this is reported across several issues and partially addressed in draft work, but there is no single product/API story that covers: discover → import/attach → show scrollback → resume. This RFC proposes that story in small phases, including one architectural hook that keeps complex flows maintainable without one-off scripts per operator.

Problem

  1. Discovery gap – Native agent chats exist on disk (transcripts, session ids) but the web "new session" flow cannot list or attach them. Users must use CLI one-liners or custom scripts.
  2. Resume vs importPOST /api/sessions/:id/resume reactivates an existing HAPI row. It does not import a chat HAPI has never seen.
  3. Spawn gap – Runner/RPC already supports resumeSessionId for several flavors, but the web spawn path has not consistently exposed it (see discussion on #572).
  4. Scrollback gap – Even after attach, the web UI may show only post-attach traffic unless transcript/history is imported into the hub store (#268, #338).

Operators routinely hit: "I have an agent chat about project X; I want it in HAPI with history, from my phone."

Goals

  • G1 – From the new-session UX, user can import an existing native chat or create new (clear fork in the flow).
  • G2 – Machine-local discovery of importable chats (by agent flavor, directory, recency, title/preview).
  • G3 – Import attaches native resumeSessionId, preserves agent context, and backfills hub messages where feasible so the web thread is usable.
  • G4 – One extensibility point for flows that need reasoning/disambiguation (e.g. user describes a chat in prose instead of picking a row) without bolting logic into the web app.

Non-goals (this RFC)

  • Replacing native agent session pickers inside Cursor/Claude/Codex UIs.
  • Full-fidelity replay of every tool/sidechain event in imported transcripts.
  • Requiring a separate hosted LLM product or API keys beyond agents the user already runs.

Related work

Item Notes
PR #518 Draft: import existing Codex/Claude sessions, ImportExistingModal, import APIs, runtime config – strong overlap with G1–G3 for codex/claude
#572 Cursor chats started outside HAPI – import/resume from web
#610 Closed; maintainer bot noted missing web discover/import for native sessions
#268 Codex pre-attach history missing in web
#338 Resume/import history not visible after remote switch
#435 Reuse local session (community ask)

This RFC is meant to coordinate these threads, not duplicate them.

Proposal

Phase 1 – Web entry + spawn contract (smallest shippable)
  • New-session screen: explicit Create new vs Import existing (not only an extra button buried in the form).
  • Expose resumeSessionId on POST /api/machines/:id/spawn end-to-end (schema, hub route, web client) for all supported flavors including Cursor.
  • Import path: user picks machine → directory → agent flavor → spawns with resumeSessionId.
  • Document that agent brain continuity comes from native resume; hub row may start empty until traffic or Phase 2 backfill.

Acceptance: User imports a known Cursor/Codex/Claude id from web without CLI; session appears in list; agent answers "where did we leave off?" with native context.

Phase 2 – Discovery + scrollback
  • Runner RPC + hub API, e.g. GET /api/machines/:id/importable-sessions?directory=&agent= (name bikeshedding OK).
  • Returns: externalSessionId, cwd, agent, previewTitle, previewPrompt, updatedAt, alreadyImported, importedHapiSessionId.
  • Security: same workspace-root rules as spawn/list-directory.
  • Import action: spawn + transcript backfill into messages with correct invoked_at (queued UI must not treat historical rows as pending user sends).
  • Extend discovery beyond codex/claude as flavors gain stable transcript layout (Cursor priority per #572).

Align implementation with PR #518 where it already exists; use this RFC as the checklist for Cursor + spawn wiring + backfill semantics.

Phase 3 – Hub-scoped operator context (architecture hook)

Some flows cannot be pure REST + forms:

  • User describes a chat in prose ("issue with X in ~/coding/foo").
  • Disambiguation among several matches in the same repo.
  • Follow-up actions across multiple HAPI sessions (attach A, summarize B, open C).

Proposal: introduce a hub-scoped operator session (name bikeshedding: operator, control, meta):

  • One long-lived session per machine/namespace (or explicit user action to open it).
  • Agent flavor is user-selected (cursor, claude, codex, …) – same stack as project sessions, not a new model vendor.
  • Tool surface is hub/runner RPCs (list importables, attach, list sessions, read session summary) rather than repo editing.
  • Web/voice/CLI front ends call into this session when they need reasoning; deterministic UI continues to use Phase 1–2 APIs directly.

Import is the first consumer: NL-assisted attach is the proof this hook is needed. Later consumers (status triage, cross-session questions) reuse the same primitive instead of new one-off scripts.

This is intentionally narrow: the operator session is not a second product UI – it is the place HAPI invokes an agent above project sessions when the control plane itself needs a brain.

Suggested UX sketch (Phase 1–2)

[+] →  Create new session  |  Import existing chat
                |
                +→ Import: Machine → Directory → Agent tabs
                     → List (search/filter on title, path, id)
                     → [Import] → open HAPI session

Optional later: "Describe the chat…" on Import screen → routes to operator session (Phase 3).

Open questions for maintainers

  1. Should import merge into an inactive HAPI row with history (reconnect) vs always spawn a new row when only native id is known?
  2. Preferred API shape: extend spawn vs dedicated POST .../import?
  3. Is PR #518 the implementation vehicle for Phase 2 codex/claude, with Phase 1/Cursor as follow-up commits?
  4. Naming/visibility for the Phase 3 operator session in the session list (pinned? hidden? separate nav?).

Why one RFC

Without a shared direction, we risk:

  • Web spawn missing resumeSessionId while runner supports it.
  • Import UI for two flavors while Cursor (#572) stays manual.
  • Transcript backfill fixed in one PR but regressions in queued-message semantics (#268/#338).
  • Every advanced flow becoming operator bash (not maintainable for mobile users).

A phased RFC keeps Phase 1–2 mergeable independently while making Phase 3 explicit before ad-hoc NL features sprawl across web and voice.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the POST /api/machines/:id/spawn path and its resumeSessionId handling, then review PR #518 and the related Cursor work in #572. The RFC spans phased web, runner, API, transcript, and operator-session changes; completion requires maintainers to choose the open API and architecture questions and meet the stated Phase 1–2 acceptance goals.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend, full-stack
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.