clean out the per-container architecture's remnants

The first iteration gave every user their own Docker container: the user's whole
world lived inside it, and only the super admin could see the real filesystem.
That model is gone, but its scaffolding was still in the tree, and it had already
cost time today — the /usr/local/bin/claude symlink removed a few commits ago
existed only because the bwrap jail ro-bound /usr and could not see the
installer's target.

Deleted:
  generate-container-context.ts   built the CLAUDE.md and settings.json that told
                                  an agent what its container looked like. Its
                                  only importer was the provisioning removed in
                                  the previous commit, so it had zero consumers.
  getUserPiConfigDir              pointed into the managed container home. No
                                  consumers anywhere in the tree.

Renamed:
  DATA_PATH/<email>/.container-context -> agent-config. It holds one file, the
  MCP server config handed to the CLI, and has nothing to do with containers. The
  path is written and consumed through a return value, so nothing else reads it;
  an old directory left on disk is inert.

Documented rather than removed, because both still have live callers and pulling
them out is a refactor rather than a cleanup:
  getHomeDir        the container's home. Nothing executes there now — terminals,
                    chats and task runs all use getOwnerHomeDir — but it survives
                    as that function's fallback and in pipeline-executor.
  toShellUsername   named for deriving a Linux username inside the container,
                    32-char limit and all. Nothing creates a Linux user now; the
                    value ends up only as a claim in the signed task token, so it
                    is a sanitiser wearing an old name. Unpicking it means
                    changing that token and WSData.

Nothing to clean on disk: DATA_PATH/<email> has no home/ tree and no
.container-context/. The docs that still mention any of this are the two marked
"Historical" at the top, which are records of what was true then and should keep
saying so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-04 13:41:16 +00:00
co-authored by Claude Opus 5
parent 99f1006669
commit b21cfc2376
3 changed files with 17 additions and 178 deletions
+11 -4
View File
@@ -31,15 +31,17 @@ export const AGENT_CONFIG_DIR = join(homedir(), '.pi', 'agent');
export const SEED_PATH = resolve(import.meta.dir, '../../seed');
// The managed home under DATA_PATH — what provisioning seeds and what the generated Claude config
// points at. Distinct from the owner's real login home below.
// The managed home under DATA_PATH. A remnant of the first architecture, where every user ran inside
// their own Docker container and this was that container's home — seeded by provisioning, described to
// the agent by a generated CLAUDE.md. Both of those are gone, and nothing executes here any more:
// terminals, chats and task runs all use getOwnerHomeDir below. It survives only as that function's
// fallback for when HOME_DIR is unset, and in pipeline-executor.
export const getHomeDir = (email: string) => join(DATA_PATH, email, 'home');
// Where the owner's sessions actually run: their real login home when HOME_DIR is set, so platform
// terminals/chats/tasks share config and credentials with the shell they use outside Officer.
export const getOwnerHomeDir = (email: string): string => process.env.HOME_DIR ?? getHomeDir(email);
export const getUserPiConfigDir = (email: string) => join(DATA_PATH, email, 'home', '.pi', 'agent');
export const getTmpAttachmentsDir = (email: string) => join(DATA_PATH, email, 'attachments', 'tmp');
@@ -53,7 +55,12 @@ export const getEmailDbPath = (ownerEmail: string, accountEmail: string) =>
export const getEmailAttachmentCacheDir = (ownerEmail: string) =>
join(getEmailAccountsDir(ownerEmail), 'attachment_cache');
/** Derive a valid Linux username from a display username or email. */
// Sanitises a display username or email into a bare, lowercase, shell-safe token. The name and the
// 32-char Linux limit are the last trace of the per-container architecture, where this really did name
// a Linux user inside the user's container. Nothing creates a Linux user now — the value is carried
// through the websocket/job payloads and ends up only as a claim inside the signed task token, so this
// is a sanitiser rather than an account name. Left in place because unpicking it means changing what
// goes into that token and into WSData, which is a wider change than a cleanup.
export const toShellUsername = (username: string, email: string): string => {
const raw = username || email.split('@')[0]!;
// Replace invalid chars, lowercase, truncate to 32 chars