General Text & Computing Company

Agent Access

Two ways to let an AI agent (or any script) read and edit your workspace files, safely and on your terms:

  • An agent seat. A credential you mint for one workspace. The agent uses it from anywhere, with no General Text app running, and its writes are encrypted and signed on its side exactly like a member's. This is how an agent pushes an app to you.
  • Local agent access. A desktop-only, opt-in bridge on your own machine, for scripts and agents working beside the running app.

Both speak the same gt command set, so an agent doesn't care which one it has.

An agent seat

People → Agent seats → Add agent seat, on the workspace you want the agent in. Give the seat a name. Your browser generates the seat's own encryption identity, hands the server only its public keys, seals the workspace key to it, and shows you a credential once. We never see the credential: it carries the seat's token and private keys, and the server keeps only a hash of the token.

Give the credential to the agent. With Node installed, nothing else is needed:

curl -fsSLo ~/.generaltext/gt.mjs --create-dirs https://www.generaltext.org/gt.mjs
node ~/.generaltext/gt.mjs seat add '<credential>' --name household
alias gt='node ~/.generaltext/gt.mjs'

gt status                      # which workspace, how many files, who the seat is
gt ls
gt cat notes/todo.md
printf '%s' "# Hello" | gt write hello.md
gt app ls                      # the apps here: what each opens, and where it publishes
gt app fork @someone/their-app # fork a gallery app into this workspace
gt app create reading-log      # an app, with an empty draft
gt app draft push reading-log ./my-app
gt app url reading-log --version draft   # open this and look at it
gt app save reading-log        # freeze the draft as a version

For Claude Code, register the MCP server with the credential in its environment instead:

curl -fsSLo ~/.generaltext/gt-mcp.mjs --create-dirs https://www.generaltext.org/gt-mcp.mjs
claude mcp add generaltext -e GT_SEAT=<credential> -- node ~/.generaltext/gt-mcp.mjs

What a seat can and cannot do:

  • One workspace. The seat sees that workspace and nothing else: not your other workspaces, not people, not billing. Requests outside it are refused.
  • Reads and writes like a member. Files it writes appear on every device within seconds and are captured in file history. Its edits are signed with its own key, so other devices can tell what the agent wrote.
  • Forks apps. gt app fork @handle/slug takes a gallery app into the workspace at the version it takes; gt app fork <app> --as <name> copies one that is already here, under a new name and without its data. It cannot publish, unlist or delete a gallery app: those need a workspace admin, and a seat is a member.
  • Builds apps, through the draft. An app is a stack of versions and the draft is the working one, so an agent writes the draft, you look at it, and it is saved as a version when it is right. gt app draft push <app> <dir> writes a folder holding gt.json and index.html (or one index.html with an inline manifest) as a hash-verified unit; it is whole-bundle, so a file the push leaves out is a file the draft no longer has. A push does not mint a version, which is the point: an agent cannot ship something nobody has seen. gt app url <app> --version draft is the link you open to look. Free-form writes to an app's code or its record are refused; an app is written as one piece.
  • Bound to one workspace's gallery identity. An app is owned by the workspace it lives in: a version published from here lands under this workspace's handle. gt status names that handle and gt app ls names each app's listing, so an agent can tell whether it is rebuilding the app that owns a listing or making a second one beside it.
  • Revocable. Revoke the seat on People: its token stops working immediately and it receives nothing further. Like a former member, it keeps a copy of whatever had already synced to it.
  • Bound by the workspace's plan. A workspace whose subscription has lapsed is read-only, and a free workspace holds three apps; a write the server refuses comes back to the agent as one sentence saying which cap it hit, not a stack trace.

One seat per workspace is included, on free workspaces too. A seat is not a person and is never billed as one.

Local agent access (desktop)

Off by default, bound to your own machine, and it only works while the app is running and unlocked.

Turn it on

Settings → You → Storage → Allow local agent access. That starts a small server bound to 127.0.0.1 (your machine only), mints a per-session token, and installs a tiny command-line tool at ~/.generaltext/gt.mjs. Turn it off anytime; the server stops and the token is discarded.

Use it yourself (a terminal)

The CLI reads the endpoint + token from ~/.generaltext/ automatically, so there's nothing to configure. Give yourself a short gt command with a one-line alias:

# add to ~/.zshrc (or ~/.bashrc) to keep it; or just paste it into your shell to try now
alias gt='node ~/.generaltext/gt.mjs'

gt workspaces                                   # see your workspaces
gt -w "My Workspace" list                       # files in one (by name or id)
gt -w "My Workspace" cat notes/todo.md
printf '%s' "# Hello" | gt -w "My Workspace" write hello.md

Want a permanent gt on your PATH (so any tool, not just your shell, can use it)? The installed script is executable, so symlink it into a bin directory:

ln -sf ~/.generaltext/gt.mjs /usr/local/bin/gt   # or ~/.local/bin/gt if that's on your PATH
gt workspaces

Point an agent at it

No setup on the agent's side. The tool runs with Node, which coding agents often already have. Copy the init prompt from the settings panel and paste it to your agent. It's written to have the agent verify the connection first, list your workspaces, and ask you which one to work in before it changes anything, so you stay in control of where it acts:

1. node ~/.generaltext/gt.mjs workspaces      → confirms it can connect + lists workspaces
2. the agent asks you which workspace to use
3. you pick; it passes -w "<that workspace>" on every command from then on

An agent's changes go through the exact same path as your own edits: encrypted, versioned, and synced to every device. (Prefer native tooling? The panel also shows a one-line command to register a Model Context Protocol server instead of the CLI.)

Choosing a workspace

An agent names the workspace it wants with -w (by name or id). You don't have to keep that workspace open: the app attaches to it in the background and keeps working it while you do other things, so a long-running task isn't interrupted when you switch around. An idle attachment is released on its own after a while.

What's protected (local access)

  • You opt in per machine, and it only runs while the app is open and your identity is unlocked.
  • Loopback + token. The bridge listens only on your own machine and requires the session token, so a web page or another user can't reach it.
  • App internals are off-limits. An agent can read and write your files, but can't alter an app's code or records, only its data.
  • Everything syncs like a normal edit, so an agent's changes appear on your other devices and are captured in file history (so you can review or roll back).

A single file larger than the per-change sync limit is rejected with a clear message; split it into smaller files (agents do this well when asked).

Building an app with an agent

Every app has one draft: its working version, in the workspace, beside the versions it has saved. An agent with a seat writes that draft, and Build on the app's page shows the draft running beside its files while the agent keeps working.

gt app ls                                  # what is already here, and what it opens
gt app create reading-log                  # skip if it already exists
gt app draft reading-log                   # open the working version
gt app draft push reading-log ./my-app     # write your folder into it
gt app url reading-log --version draft     # the link to open and look
gt app save reading-log                    # freeze it as a version

Nothing here runs on the agent's machine, so the same commands work from your laptop, a server, or a phone conversation, and what the agent wrote is on every device before you look at it.

The draft gets a copy of the app's data, not the real files, so a half-written version cannot wreck anything you care about. The copy is thrown away when the draft is saved or discarded. Pass --no-data to run it against the real files instead.

A push does not make a version. The number is chosen when you save, against what is already there, so an agent cannot ship something nobody has looked at. gt app draft ls <app> shows what the draft would change, and gt app versions <app> shows the whole stack. Saving is not publishing either: putting a version in the gallery is a separate act, per version, on the app's page.

For app makers

If you build General Text apps, document your app's data format in its README (see Publishing to the Gallery). The README travels with your app, so an agent working through Agent Access can read it and then read and write your app's data correctly, the same way a person would.