Skip to content

Replace the RFS file plane with a storage-independent agent Space API and per-run credentials #359

Open

Description

@ultmaster

Problem

External agents reach a Space through RFS ($HUABU_RFS_URL, the huabu-rfs client, guided by apps/server/src/prompt/external-agent/rfs-cli/access-huabu.md). Two gaps make that unusable for a multi-user deployment.

1. RFS refuses every request off Disk. A route-wide hook in apps/server/src/modules/remote_fs/rfs.route.ts returns 409 unless both the structured and blob backends are Disk (the space-file-plane capability in apps/server/src/modules/storage/capabilities.ts). On Postgres + Azure, the shape a Bubble deployment needs, an external agent can't use download, upload, query, execute, agent, service or skill. That holds for administrators too.

Only download and upload really need Disk. They resolve a path through safeResolve into the Space directory and stream the file, and paths like nodes/<label>.md exist only because Disk names its sidecar files after labels. query and execute already run on the portable Space query and command layer, but they sit behind the same hook.

The capability's rationale says an external agent off Disk "reaches it through the Canvas API", but nothing in the agent prompts tells it so.

2. The RFS credential is unrestricted. The client sends Authorization: Bearer $AGENTLET_TOKEN. Agentlet gives that token, the daemon's own machine credential, to every agent process, and it reaches every Workspace and Space. The Workspace and Space in the URL (/api/rfs/w/<workspaceId>/<canvasId>) only say where to look. They don't limit access, because an agent can rewrite the URL. For this reason, #357 keeps external agents administrator-only.

Proposal

Replace the "Space as files" model with one agent-facing Space API that works on every storage backend.

Need Shape
Orient, inspect, search query as it is
Change the Space execute as it is
A node's body Fetched by node id. Rendered from the record on any backend, with its revision for conditional requests.
An artifact or snapshot Fetched by artifact key from blob storage
Staging bytes for a command Upload into blob storage, then referenced by an execute command
Delegation, services, guides agent, service, skill as they are

The client should still write fetched bytes to an output file. An external agent works with its own tools (read, grep, vision, scripts), and keeping large bodies, PDFs, snapshots and Service Packages out of its context is the reason bytes arrive as files. Only the address changes, from a Disk path to a node id or artifact key.

Agents shouldn't use the web app's /api/canvas routes. Those are shaped for the UI (live updates, change-review records, browser sessions). The agent API stays agent-shaped (bounded results, generated ids, --help guidance, per-command results) and calls the same Space and storage code the web routes use.

Credentials.

  • Huabu issues a per-run token bound to the person, Workspace, Space and thread.
  • The agent API goes through the same request admission and Space-access check as browser requests, running in the run's Workspace scope.
  • Agentlet stops handing agent processes the daemon token, or Huabu stops accepting that token on this API. Without one of these, a scoped token doesn't contain anything.

With both parts done, members could run external agents, which lifts that limitation of #357.

Scope

  • Lift the blanket space-file-plane refusal for the portable operations, and serve node bodies and artifacts by id or key from records and blob storage.
  • Update access-huabu.md and its sub-guides, the huabu-rfs client (packages/client-runtime/src/rfs.ts) and the shared contract in packages/shared/src/types/api/rfs.ts.
  • Rename "RFS" and HUABU_RFS_URL, since the file-system model no longer applies. Keep a compatibility path for existing agents.
  • Write the design as a proposal under docs/proposals/. It replaces the file-plane parts of docs/proposals/agent-reachback-rfs.md.
  • Coordinate the Agentlet change in external/agentlet.

Related

— posted by Claude Code (Claude Opus 5.5) (via the issue-tracker skill)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions