term-llm contain creates named Docker Compose workspaces for long-running agents. Each workspace has its own compose file, .env, Docker volume, Web UI, jobs service, memory database, sessions, skills, and agent configuration.
The current happy path is term-llm contain new followed by term-llm contain start. You do not need to clone the term-llm repo or hand-copy seed directories.
Prerequisites#
- Docker with Compose v2
term-llminstalled on the host- At least one provider credential, or a plan to configure credentials inside the container later
Create an agent workspace#
term-llm contain new myagentBy default this uses the managed agent template. It creates a global workspace under your term-llm config directory:
~/.config/term-llm/containers/myagent/
├── compose.yaml # source of truth for Docker Compose
├── .env # provider credentials, Web UI token/port, image settings
└── README.md # workspace-specific commands and notescontain new prompts for provider credentials and useful settings unless you pass --no-input and --set values:
term-llm contain new myagent \
--no-input \
--set provider=anthropic \
--set web_port=8081The generated .env is private (0600). It contains the selected provider, optional API keys/OAuth bootstrap data, WEB_PORT, WEB_BASE_PATH, and a generated WEB_TOKEN for bearer-authenticated Web UI access.
Start and open it#
If you did not start it from the creation prompt:
term-llm contain start myagentThe Web UI is exposed at:
http://localhost:<WEB_PORT>/chatUse the bearer token printed by contain new or stored in the workspace .env.
You can also chat from the terminal using the built-in exec recipe:
term-llm contain exec myagent agentOpen a shell inside the workspace:
term-llm contain shell myagentShells open as the non-root agent user in /home/agent. Use explicit passwordless sudo when root privileges are needed.
What gets bootstrapped#
The Compose service builds the managed agent image and mounts one persistent Docker volume at /home/agent. On first boot, the image copies bootstrap files from /opt/term-llm/bootstrap into that volume. The image also seeds the term-llm source checkout at /home/agent/source/term-llm, with documentation under /home/agent/source/term-llm/docs-site/content.
Use /home/agent/source/<project> for source checkouts and code projects you want to persist. Use /home/agent/Files for downloadable files served by the Web UI. Avoid putting durable work in /tmp, /root, or other image-only paths.
/home/agent/.config/term-llm/
├── agents/myagent/
│ ├── agent.yaml
│ ├── system.md
│ ├── soul.md
│ ├── memory/recent.md
│ └── scripts/
├── services/
│ ├── webui/run
│ ├── jobs/run
│ └── bootstrap-jobs/run
├── skills/
│ ├── jobs/SKILL.md
│ ├── memory/SKILL.md
│ ├── self/SKILL.md
│ └── widgets/SKILL.md
├── source/
│ └── term-llm/ # runtime source and docs-site/content documentation
└── init.shAfter first boot, the volume is the source of truth. Future boots ignore image bootstrap files and run /home/agent/.config/term-llm/init.sh, which reinstalls persisted runit service definitions into /etc/sv and links them into /etc/runit/runsvdir.
The service supervisor runs as root. The Web UI, jobs server, first-boot bootstrap-jobs one-shot, shells, and normal agent work run as the agent Linux user.
Services#
| Service | What it does |
|---|---|
webui |
Runs term-llm serve web on port 8081 inside the container. |
jobs |
Runs term-llm serve jobs on port 8080 inside the container. |
bootstrap-jobs |
Creates default scheduled jobs on first boot, then removes its persisted service definition and exits. |
The Web UI service uses --no-projects because each container is already a dedicated, persistent agent environment rather than a host for unrelated project roots. Single-workspace mode is a first-class deployment choice for personal agents like these, without an extra project-registry layer. The service starts in /home/agent, so repository-aware features use the agent’s home as their starting point.
term-llm serve web \
--agent myagent \
--no-projects \
--base-path /chat \
--host 0.0.0.0 \
--port 8081 \
--auth bearer \
--yolo \
--files-dir /home/agent/Files \
--widgets-dir /home/agent/.config/term-llm/widgetsCheck service status from the host:
term-llm contain exec myagent -- sv status /etc/runit/runsvdir/webui/
term-llm contain exec myagent -- sv status /etc/runit/runsvdir/jobs/Restart a service:
term-llm contain exec myagent -- sudo sv restart /etc/runit/runsvdir/webui/Default jobs#
On first boot, bootstrap-jobs waits for the jobs API, creates the defaults, and then removes itself from the persisted service set:
| Job | Schedule | What it does |
|---|---|---|
mine-sessions |
Every 30 min | Mines session transcripts into memory fragments. |
update-recent |
Every 10 min | Promotes recent fragments into memory/recent.md. |
system-upgrade |
Daily at 05:00 UTC | Upgrades distro packages (pacman on Arch, dnf on Fedora). |
Inspect and operate them inside the workspace:
term-llm contain exec myagent -- term-llm jobs list
term-llm contain exec myagent -- term-llm jobs runs mine-sessions --limit 10
term-llm contain exec myagent -- term-llm jobs update mine-sessions --data '{"enabled": false}'Skills and memory#
Fresh agent containers include a small default skill set:
| Skill | Purpose |
|---|---|
jobs |
Inspect and manage jobs and runit services. |
memory |
Search and update persistent memory fragments. |
self |
Safely modify the agent’s own prompt/config/scripts. |
widgets |
Build, install, inspect, and debug Web UI widgets. |
Skills are copied to /home/agent/.config/term-llm/skills/ and the first-boot config.yaml enables the skills system with auto-invocation.
Memory fragments live in term-llm’s database on the persistent volume. memory/recent.md is seeded empty and maintained by the default jobs. memory/palace.md is a small stable-context template for durable, high-value facts. Prefer memory commands over hand-editing generated summaries.
Widgets#
Add widget apps under:
/home/agent/.config/term-llm/widgets/They are served under:
/chat/widgets/<widget-name>/The bundled widgets skill documents the container-specific operational workflow: inspect widget support, create manifests, reload the widget registry through /chat/admin/widgets/reload, and smoke-test routes. The Web UI widgets guide covers the complete manifest, proxy, lifecycle, and security contract. You do not need to restart the Web UI just to add or update a widget; restart it only for service flag changes, binary upgrades, or if the admin reload endpoint is unavailable.
Updating#
Update the host term-llm first, then rebuild/recreate the workspace image:
term-llm contain rebuild myagentState is preserved in the Docker volume. Rebuilds update the managed image and binary but do not generally overwrite live agent config already copied into /home/agent. The image does apply narrowly detected service migrations when required for compatibility; custom Web UI launchers and services with an explicit --projects or --no-projects choice are left untouched.
Removing a workspace#
Stopping preserves state:
term-llm contain stop myagentRemoval is destructive and asks for confirmation:
term-llm contain rm myagentThis runs Docker Compose down with volumes and deletes the workspace config directory.
Running multiple agents#
Each workspace is independent:
term-llm contain new agent-a --set web_port=8081
term-llm contain new agent-b --set web_port=8082
term-llm contain start agent-a
term-llm contain start agent-bEach gets its own Compose project, persistent volume, Web UI token, jobs, memory, sessions, and live agent files.
Advanced: custom bootstrap seed#
The managed image supports an optional static /seed mount containing bootstrap.yaml. If present, /seed replaces the image bootstrap source for first boot only. After the bootstrap sentinel exists on the volume, /seed is ignored. For normal use, prefer the built-in contain new template and edit the live files through the agent’s self-modification workflow.