/** * Local directory layout for Agent State and Project config. * * Strictly follows the `~/.penguin/data//agents//...` structure. * This module only provides constants and pure path functions; it never creates directories or reads/writes files. * Docs: /docs/sessions-and-traces § "Data layout". */ import os from "node:os"; import path from "node:path"; /** Default Project id used when none is specified. */ export const DEFAULT_PROJECT_ID = "default_project"; /** Default Agent id used when none is specified. */ export const DEFAULT_AGENT_ID = "default_agent"; /** * Resolves the local data root directory. * Prefers the `PENGUIN_HOME` environment variable, otherwise falls back to `~/.penguin/data` * (under the hidden `~/.penguin` home so it never collides with unrelated folders, and in a * `data/` subdir kept separate from the installer's binaries under `~/.penguin`). */ export function resolveRoot(): string { return process.env.PENGUIN_HOME ?? path.join(os.homedir(), ".penguin", "data"); } /** `/`. */ export function projectDir(root: string, projectId: string): string { return path.join(root, projectId); } /** * `/agents` from an already-resolved Project directory path — the single * definition point of the agents-container layout. */ export function agentsDirFrom(projectDirPath: string): string { return path.join(projectDirPath, "agents"); } /** `/agents`, the container directory holding every Agent in the Project. */ export function agentsDir(root: string, projectId: string): string { return agentsDirFrom(projectDir(root, projectId)); } /** `/agents/`. */ export function agentDir(root: string, projectId: string, agentId: string): string { return path.join(agentsDir(root, projectId), agentId); } /** `/agent_state`. */ export function agentStateDir(root: string, projectId: string, agentId: string): string { return path.join(agentDir(root, projectId, agentId), "agent_state"); } /** `/traces`. */ export function tracesDir(root: string, projectId: string, agentId: string): string { return path.join(agentDir(root, projectId, agentId), "traces"); } /** `/scratchpad`, the Agent's temporary/draft file directory (the model creates a subdirectory per Session id). */ export function scratchpadDir(root: string, projectId: string, agentId: string): string { return path.join(agentDir(root, projectId, agentId), "scratchpad"); } /** `/workspaces`. */ export function workspacesDir(root: string, projectId: string, agentId: string): string { return path.join(agentDir(root, projectId, agentId), "workspaces"); } /** * `/scratchpad//GOAL.yaml`, the goal-mode control file of one Session * (sibling of the model's PLAN.md convention; see goal/goal-file.ts for field ownership). */ export function goalFilePath( root: string, projectId: string, agentId: string, sessionId: string, ): string { return path.join(scratchpadDir(root, projectId, agentId), sessionId, "GOAL.yaml"); } /** * `/.project_config.toml`, the Project's single config file (a hidden file, not * shown by default `ls`, written with mode 0600; model entries are inlined with their credential, * see state/project-config.ts). */ export function projectConfigPath(root: string, projectId: string): string { return path.join(projectDir(root, projectId), ".project_config.toml"); } /** `/system_config.yaml`. */ export function systemConfigPath(root: string, projectId: string, agentId: string): string { return path.join(agentStateDir(root, projectId, agentId), "system_config.yaml"); } /** `/AGENTS.md`. */ export function agentsMdPath(root: string, projectId: string, agentId: string): string { return path.join(agentStateDir(root, projectId, agentId), "AGENTS.md"); } /** `/.vault.toml`, the Agent-level environment-variable vault (see state/agent-vault.ts). */ export function agentVaultPath(root: string, projectId: string, agentId: string): string { return path.join(agentStateDir(root, projectId, agentId), ".vault.toml"); } /** `/tools`, reserved for user-defined Tool config. */ export function toolsDir(root: string, projectId: string, agentId: string): string { return path.join(agentStateDir(root, projectId, agentId), "tools"); } /** `/memory`. */ export function memoryDir(root: string, projectId: string, agentId: string): string { return path.join(agentStateDir(root, projectId, agentId), "memory"); } /** `/skills`. */ export function skillsDir(root: string, projectId: string, agentId: string): string { return path.join(agentStateDir(root, projectId, agentId), "skills"); } /** `/schedule`, the scheduled-task directory (doesn't exist when unconfigured). */ export function scheduleDir(root: string, projectId: string, agentId: string): string { return path.join(agentStateDir(root, projectId, agentId), "schedule"); } /** `/benchmarks`, the capability-evaluation question bank and scores (doesn't exist when unconfigured). */ export function benchmarksDir(root: string, projectId: string, agentId: string): string { return path.join(agentDir(root, projectId, agentId), "benchmarks"); } /** `/snapshots`, Agent State version snapshots (doesn't exist when unconfigured). */ export function snapshotsDir(root: string, projectId: string, agentId: string): string { return path.join(agentDir(root, projectId, agentId), "snapshots"); }