Skip to content

About

No description, website, or topics provided.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

LayerFS Connect

Connect is a desktop coding agent powered by Pi, with bash and subagents as its tool surface. Chat runs real model conversations in a local folder or a managed LayerFS workspace; project views show their saved history.

Install with an agent

Paste this into a coding agent (Claude Code, Codex, …) opened in the folder that should hold both repositories:

Install LayerFS Connect on this machine. Work in the current folder; Connect
and LayerFS sit side by side in it as ./layerfs-connect and ./layerfs.

Branches: Connect is used at its `main`. LayerFS is used at the tip of its
`layerfs_v2_0_0` branch, through a worktree at
./layerfs/.claude/worktrees/connect-main that Connect's package.json links to.

1. Check the prerequisites and report any that are missing; ask me before
   installing system software: git, Node 22.15 or later, pnpm (via
   `corepack enable`; the version is pinned in package.json), Docker (running),
   jq and python3.
2. Clone what is missing, and leave existing checkouts on their branches:
   https://github.com/Ephemeral-AI-Lab/layerfs-connect into ./layerfs-connect
   (branch main) and https://github.com/Ephemeral-AI-Lab/layerfs into ./layerfs.
3. Make the LayerFS worktree Connect builds against:
     git -C layerfs fetch origin layerfs_v2_0_0
     git -C layerfs worktree add --detach .claude/worktrees/connect-main origin/layerfs_v2_0_0
   If that worktree already exists, do not recreate it. If it is clean, move
   it to the branch tip with
     git -C layerfs/.claude/worktrees/connect-main checkout --detach origin/layerfs_v2_0_0
   If it has uncommitted changes, stop and tell me.
4. In ./layerfs-connect run `pnpm install`. Confirm node_modules/@layerfs/cli
   resolves into the connect-main worktree.
5. Verify: `pnpm typecheck` and `pnpm test:agents` (a local test model; no
   API key needed).
6. Managed LayerFS projects need ~/.layerfs-connect/settings.json:
     { "image": "sha256:…", "bundle": "/abs/path/build-linux-…", "containerPrefix": "lfc-" }
   `image` is the sandbox image's ID, and `bundle` is a sealed Linux LayerFS
   build of the connect-main worktree. Make it by following
   layerfs/docs/general/parallel-worktrees.md (register, prepare, then
   `build --platform linux`) with images that already exist locally. Do not
   pull, build or retag Docker images without asking me. If settings.json
   exists, back it up before changing it. Then run the real-workspace check
   from README.md's "Develop" section (CONNECT_REAL_LAYERFS=1 …). Local-folder
   chats work without this step; if it is blocked, say why and go on.
7. Start the app with `pnpm dev`. Do not ask for or store model API keys;
   I add models in the app (Chat header > model dropdown > Manage models).

Never edit, commit to or switch branches in the LayerFS repository beyond the
worktree above, and do not commit in layerfs-connect. Finish with a short
report: the commit each repository is on, which checks passed, and anything
skipped or blocked.

Start an agent session

  1. Run pnpm install, then pnpm dev in this repository.
  2. Open the model dropdown in the Chat header and choose Manage models. Enter the provider, API URL and key, then use Fetch models to register the whole model list and connection settings at once. All fetched models appear in the Chat header's model selector immediately, keeping the current selection and thinking level. There is no need to add or save models one by one; manual IDs remain available. Supported endpoints return their live list; subscription and other configured native providers without a listing API use their built-in catalog. New custom providers default to Chat Completions; choose another API format when needed. Save & test saves the configuration and makes a small real model request; provider errors appear in the dialog.
  3. Open Workspace settings above the conversation. For Local folder only, choose the shell's working directory with Browse, or enter its absolute path. Commands in this mode act directly on that local folder.
  4. Alternatively choose a LayerFS project, or open a project and click New chat. The first message creates a conversation with its own chat-<session id> branch and managed container workspace. The lead agent and all its subagents run bash in that workspace, rather than the local folder or the project's original import source.
  5. Send a task. Text and reasoning arrive from Pi as they stream. Tool cards show commands and output; subagent cards show delegated tasks and results.

Model Settings opens with empty provider and model fields. Add provider starts another blank configuration; Save provider stores its connection without requiring a model or changing the current selection. Saved provider cards let you edit each connection independently. Choose one of its saved models explicitly, or enter an ID and use Save model. Several providers can keep different endpoints, keys and model limits at the same time. Expand Request headers below the API key to add name/value pairs for that provider. Values are hidden by default and sent as literal text with model discovery, connection tests and chat requests. Save the provider or model to keep them; remove its rows and save to clear them. Each saved provider has a × button. Confirming Delete provider removes its connection, credentials and model settings; saved conversations remain. Deleting the currently selected provider clears the main model selection.

Project conversations share one workspace between the lead and child agents. Their bash commands run one at a time, starting at the workspace root; use cd within a command for a subdirectory. Changed files are saved to the conversation's branch after each command, including changes made before an error or interruption once the command is confirmed stopped. Read-only commands do not create extra commits. Connect does not automatically merge or publish these commits to main.

The workspace row shows the host's actual branch, mounted path, execution and save state, and latest commit. Branch history opens that branch in the project's History, which refreshes as commits arrive. Stop, conversation deletion and graceful host shutdown stop active work, save remaining changes, unmount the workspace and close its sandbox. An incomplete cleanup remains visible as an error and retains the workspace for retry. Continuing a stopped conversation mounts the same saved branch again.

Project commands do not leave background processes running after they finish: Connect stops the command's process group and descendants before saving. Run checks in the foreground. Pi may put large-output logs on the host; its fullOutputPath cannot be read by container bash. Redirect large output to a file inside the workspace when the agent needs to inspect it later.

Chat uses full access by default, including existing conversations when Connect opens. Root and child bash commands execute without individual approval prompts. The composer has no permission selector or access-confirmation dialog. Project conversations execute inside their managed LayerFS workspace; local conversations execute in the selected host folder with its OS permissions. Existing approval records remain available in the conversation history.

The square button, or Escape in the composer, stops the current task and its children, clearing pending messages. During execution, sending adds a message to Next up above the composer. Pi follows up automatically, one message at a time, after the current work finishes. Each pending message can be expanded, removed, or promoted with Steer to guide the current task after its current step finishes. Pending messages enter the conversation only when the agent starts processing them. The upper-left history button opens History with search, switching and deletion. The Context tab shows the active session; its Conversation transcript can be searched and fully expanded to inspect messages, thinking, tool arguments and output in the saved context. Compact summarizes a long idle conversation; its summary replaces earlier context entries in the transcript. This is the saved Pi context, not a full raw-history archive. New starts another conversation. Model selection and thinking intensity remain visible together in the header and can change between turns; provider settings live in the model menu. Recorded usage adds provider-reported usage from the saved main-agent Pi tree, including copied and branched history. It is not a billing ledger for new requests or the complete cost of child agents. The context ring separately shows the current context-window estimate.

The conversation menu provides Run settings before the first message and between runs: turn/runtime budgets, a default bash timeout, native retry limits and conversation instructions. Root and child agents also load the execution directory's project instructions automatically. Continue and Retry resume through Pi with completed tool results retained. Background run cards expose Stop run when Pi provides independent control; the main Stop action covers all child work. Long bash results have a paged full-output viewer.

Attach UTF-8 text files or images with the composer. Image input requires a model that supports it. Draft text, attachments and new-chat run settings are saved locally per conversation or selected project/folder. The conversation menu also supports rename, archive/restore, copying the transcript and exporting Markdown or JSON. Archiving keeps the conversation and LayerFS branch history. Connection status shows when the event stream is reconnecting and refreshes the active snapshot when it recovers. See the harness baseline for defaults, input limits and verification.

Each user message has an actions menu with Copy text, Edit & resend, Revert before this message, and Copy before this message. Reverting restores the context before that message and puts its original text back in the composer without sending it. Editing restores the same point and sends the revised text. Copying before a message creates a separate conversation with that text as its unsent draft. Duplicate chat in the conversation or history menu copies the complete active context.

For LayerFS project conversations, each user message records the file state when it enters the agent's context, including queued and steering messages. Revert and edit restore that snapshot on a new revision branch; the previous branch and Pi conversation entries remain in history. Copies receive an independent LayerFS branch and workspace. Local-folder conversations change only their chat context and continue using the original local folder. Stop active work before these operations; confirmations describe what will change.

Each history row's actions menu includes Delete conversation. Confirm it by title and folder; running conversations offer Stop and delete, which first stops the current turn and its subagents. Deleting the current conversation returns Chat to a new session. This removes saved conversation data. Local folder files stay in place; a project workspace is stopped and unmounted, while its saved LayerFS branch history is kept. A failed deletion stays open with its error and a Try again action.

Type / in Chat to open local shortcuts: /new, /history, /model, /workspace, /compact and /stop. Use Up/Down to choose, Tab to complete, Enter to run, or Escape to dismiss. Commands use the existing controls; an unknown slash command is sent as ordinary text. The small shortcut menu beside Send remembers Enter or Cmd/Ctrl+Enter; Shift+Enter adds a new line. Confirming a Chinese IME candidate does not send the message or run a command.

The workspace panel's Recent menu reuses the six most recent local folders from saved local-folder sessions. Project sessions show their managed workspace instead of a local execution path. A session keeps its bound workspace; start a new one to choose another folder or project. The composer's context ring reads Pi's current context estimate, with used, remaining and limit details. Usage is unknown immediately after compaction until the next response, or after restarting until the session runs again; this estimate is not saved as a stale percentage.

Connect stores its Pi configuration under ~/.layerfs-connect/pi/: standard auth.json credentials, models.json provider definitions, and connect-models.json for the selected model. Conversations and Pi JSONL files live under ~/.layerfs-connect/chats/<session id>/. A custom LAYERFS_CONNECT_STATE changes this root. Connect uses its own Pi directory; model secrets are kept in the host and are not returned by the settings API.

Both the lead and child agents use bash for file reads, searches, writes and edits. The pi-subagents extension supplies delegation and supervision tools; read, write, edit, find, grep and ls are not separate model tools.

The conversation controls adapt useful behavior from conecode_副本: provider-scoped model configuration, independent session streaming, stop and queued input, collapsible reasoning/tool output, slash commands, IME-aware shortcuts, workspace reuse, and context/token/cost display. Pi owns the model protocol, agent loop and session persistence.

The UI

The language control at the bottom of the sidebar switches between Simplified Chinese and English immediately. The first launch follows the system language; the selected language is saved on this device. Switching keeps the current page, forms, drafts and running agent work. Interface labels and date formats are localized; project/model names, conversation content, source code and raw tool output remain unchanged. Renderer strings live in src/renderer/src/i18n/.

The sidebar keeps four destinations: Chat, Projects, Storage and Compute. The brand is a single title with no subtitle. Demo scenarios, scripted sessions and replay controls are no longer part of the desktop UI.

  • Chat opens interactive Pi sessions, with conversation history, model and thinking controls. Its project picker lists existing user projects.
  • Projects lists existing LayerFS projects with search, refresh and New project. The sidebar's Your projects list opens each project directly. It shares the same directory with Projects and Chat, updates after creation from either entry point, and reloads saved projects when Connect starts. Each sidebar project has an × action that opens a confirmation dialog. Confirming deletes its project storage and history through the existing host API; original source folders and saved conversations remain. Failed deletions stay in the dialog for retry, and successful deletions update the shared list. The + beside Projects in the sidebar opens the same dialog. Entries marked by the host as demo runs are omitted; their stored files are kept.
  • A project page reads the project directly, without requiring a demo run. History, Storage and Sandboxes show the host's actual data; Sessions (with the Live diagram on top while a run plays) and Script appear for projects that play scenarios. Empty projects show empty states instead of sample workspaces or execution data. New chat opens a fresh draft bound to that project without starting an agent until the first message is sent.
  • Storage shows local volumes, disk and worker status. Project rows open the actual project. Remote providers remain clearly marked as planned.
  • Compute shows Docker and sandbox status, with unavailable providers disabled.

Remote Push/Pull/conflict mocks and hardcoded native sandboxes have been removed. Backend scenario fixtures and command-line test runners remain available for development; this cleanup does not delete project volumes, model configuration or saved Pi conversations.

Create a project

Choose New project in Projects, the sidebar +, or the + beside the LayerFS project field in a new Chat workspace. Enter a project name, then select Empty project or Import folder. The latter copies files from the chosen local folder into LayerFS; it does not move or delete the original folder.

Creation uses the configured local SQLite runtime and reports its actual scan, storage and import stages. A duplicate name is rejected instead of replacing a project. Runtime or Docker setup errors remain visible in the form. If status polling is interrupted, Check status resumes the existing job without submitting another creation request.

Successful creation from Projects or the sidebar opens the project. Creating from Chat selects it in the current draft. Its agent will use a managed workspace; the import source is not the execution directory. Importing also remembers the source as the local-folder choice if you later switch back to Local folder only. Empty projects keep that local-folder choice unchanged. Saved conversations keep their existing project association.

Look and motion

  • Theme: colours, radii, shadows and motion are tokens in src/renderer/src/styles.css, with light and dark modes (the system's, or CONNECT_THEME).
  • Components: shadcn components live in components/ui/. Shared motion (reveals, the sliding tab indicator, page cross-fades) lives in components/motion/.
  • Icons: LayerFS icons are SVGs in assets/icons/ (lfs-icons.tsx).

Layout

host/          the backend: a plain Node process the app starts (host/README.md)
  agents/      Pi sessions, model configuration, bash and pi-subagents integration
  runs/        scenario engine: agents, bash and subagent tools, jobs, expect checks
  parse/       splits every agent call into classified segments (workspace, fs, branch, …)
  checks/      final checks of a finished replay against its recording
scenarios/     the ten demos (scenarios/README.md)
fixtures/      the demo workspace most demos Init from
tools/         scenario tools: port, replay convert/check, connect-run
src/
  main/        Electron main process: starts the host, opens windows
  preload/     hands the host's address to the renderer
  shared/      host-api.ts, the host ↔ renderer contract
  renderer/    React UI: chat, projects, files, history, storage, compute

Where LayerFS comes from

Two branches go together: Connect works on its own main, and builds against LayerFS's layerfs_v2_0_0 branch.

Connect never installs into or edits the LayerFS repository. package.json links @layerfs/* to the api/ packages of a LayerFS worktree beside this repo, kept at the tip of LayerFS layerfs_v2_0_0 (../layerfs/.claude/worktrees/connect-main/api/{agent,backend,cli,runtime}; the folder's name is older than the branch). The worktree sits on that commit detached, so it does not follow the branch by itself; to move it forward, git -C ../layerfs fetch origin layerfs_v2_0_0 then git -C ../layerfs/.claude/worktrees/connect-main checkout --detach origin/layerfs_v2_0_0. The host loads host/resolve-layerfs.js, so @layerfs/* resolves from Connect's node_modules. Local-folder bash calls also receive this resolver; project bash runs through the host's LayerFS workspace execution bridge inside the container. The macOS worker runs a sealed Linux LayerFS build from the same worktree (tools/worktree.py build in LayerFS), named in ~/.layerfs-connect/settings.json:

{ "image": "sha256:…", "bundle": "/path/to/build-linux-…", "containerPrefix": "lfc-" }

Connect keeps its own LayerFS home (~/.layerfs-connect/home) and container prefix, so its worker (lfc-worker), Sandboxes and volumes never meet another integration's.

Develop

Needs Node 22.15 or later, pnpm, Docker and jq.

pnpm install
pnpm dev         # app with hot reload
pnpm typecheck
pnpm test:agents # real Pi/bash/subagents against a local test model; no API key needed
pnpm build       # production build into out/
pnpm start       # run the production build

With Docker running and Connect's LayerFS image/bundle configured, verify real managed workspaces in a disposable project (local test model; no API key):

CONNECT_REAL_LAYERFS=1 node --import ./host/resolve-layerfs.js --test --test-timeout=200000 host/test/agent-layerfs-real.test.js

This covers root and child bash, separate conversation branches, large UTF-8 output, saves after failed/stopped commands, immediate continuation and restored sessions. It removes its own project, worker and temporary state after the run.

Host tests (each command stays under two minutes):

node --import ./host/resolve-layerfs.js --test host/test/*.test.js tools/checks/tests/*.test.mjs

Developer scenario fixtures can still run without the window:

node --import ./host/resolve-layerfs.js host/run-demo.js tour --project <key>  # an existing project; plays in /tour_<n>/

Drive the running app's host from a terminal (it writes ~/.layerfs-connect/host.json):

node tools/connect-run.mjs start tour merge

Dev aids: CONNECT_VIEW=<hash> opens a page (chat, projects/<project>[/<tab>], storage, compute); CONNECT_SHOT=<file.png> saves a screenshot once loaded, then quits (CONNECT_SHOT_DELAY waits longer; CONNECT_EVAL=<js> runs in the page first and prints its result); CONNECT_THEME=dark|light.

About

No description, website, or topics provided.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages