Skip to content

Targets

A target is a named execution template. A session combines one profile, one target, and either a configured bundle or an existing Git project directory. The target decides where work runs, what isolation contains unrestricted agent actions, how the workspace is created, and what is removed after a verified stop.

mj setup creates a localhost raw target and one target for each usable local container runtime it discovers. Add SSH and AWS targets during setup or edit config.toml directly. Press F5 in the dashboard to refresh target capacity, or run mj doctor --smoke for end-to-end checks of local Podman, local Docker, Apple Container, and SSH Podman targets. Bare and AWS targets do not have smoke tests.

KindRuns onIsolation boundaryNew-session projectSupplemental directoriesResource choiceTarget lifecycle
local-bareLinux controller machinenoneExisting local Git directorynohost-ownedMachine persists; managed session worktree is archived and retired on stop.
local-podmanLocal Linux/WSL2rootless containerBundlecopy-on-write or read-only mountsCPU and memoryContainer and workspace storage are removed after verified stop.
local-dockerLocal Linux/WSL2Docker containerBundlecopy-on-write or read-only OverlayFS viewsCPU and memoryContainer and managed workspace volume are removed after verified stop.
apple-containerApple-silicon macOS 26+Apple container VMBundleread-only mountsCPU and memoryContainer is removed after verified stop.
ssh-bareNamed remote Linux hostnone beyond host/accountExisting remote Git directorynohost-ownedHost persists; per-session worktree/workspace is archived and retired.
ssh-podmanNamed remote Linux hostrootless containerBundleremote-host copy-on-write or read-only mountsCPU and memoryRemote container and workspace storage are removed after verified stop.
aws-ec2Your AWS accountdisposable EC2 instanceBundlecontroller-side directory snapshotEC2 instance typeInstance is terminated after verified stop.

“Verified stop” means Mjolnir has created a recovery archive and checked its SHA-256 on the controller before tearing the resource down. See Durability and recovery.

Mjolnir installs and caches its pinned harness runtimes for local-bare, ssh-bare, and aws-ec2 sessions. Local sessions use the selected profile’s existing home and credentials, while their runtime is managed independently of commands such as codex installed for native terminal use. Containers use the runtimes supplied by their image.

New workers use the versions shipped with your Mjolnir build. Upgrade an existing session’s worker to adopt those versions; running workers retain their current runtime until upgraded.

Mjolnir selects approval behavior from the target, then translates it into the chosen harness’s controls:

TargetEffective policy
local-barePreserve the profile and harness’s configured approvals.
ssh-bare, permissions = "guardian"Preserve configured approvals.
ssh-bare, permissions = "yolo"Unconstrained.
Every container and EC2 targetUnconstrained inside the isolation boundary.

The unconstrained translation is Codex agent-full-access, Claude Code bypassPermissions with its sandbox disabled, Kimi Code auto, Grok Build always-approve with its sandbox disabled, and DeepSeek Harness danger-full-access. These all approve every action; Kimi’s mode happens to be named auto but is not a risk-selective guardian.

Codex, Claude Code, and Grok Build can preserve guardian approvals on raw targets. Kimi Code and DeepSeek Harness cannot, so Mjolnir displays a prominent warning when either is selected without an isolation boundary. Read Security boundaries before choosing a raw or yolo target.

Bare targets select an existing absolute Git project directory rather than a bundle. They do not accept supplemental directory attachments or container resource sizing.

[targets.localhost]
kind = "local-bare"

The directory must exist locally and have a valid Git HEAD. When it is the repository’s primary checkout, Mjolnir creates a session-specific linked worktree under .mj/worktrees/<session-id> on branch mj/<session-id>. This keeps concurrent sessions off the primary checkout while retaining ordinary local Git object sharing. If the selected path is already a linked worktree, Mjolnir uses it as selected. Creating a managed worktree requires the primary checkout to be completely clean, including staged, unstaged, and untracked files.

Although the controller and viewer support macOS, current local-bare worker launch requires Linux. Use Apple Container or a remote target for sessions from a macOS controller.

There is no process, filesystem, or network isolation between the harness and your controller account. The harness also uses the configured profile home directly. Use this target only when you trust both the agent and its approval configuration.

[targets.builder]
kind = "ssh-bare"
host = "builder.example.com"
user = "ubuntu"
permissions = "guardian"
workspace_prefix = ".local/share/hel/workspaces"

The wizard validates an existing Git directory on the remote host. Primary checkouts are isolated with the same linked-worktree model on that host and must first be completely clean, including untracked files. The remote machine persists across sessions. Mjolnir-created worktrees and worker/profile staging areas are lifecycle-managed; a linked worktree you selected yourself remains yours. workspace_prefix controls a separate per-session lifecycle/cleanup path, not the selected project or its linked-worktree location.

The host does not need a preinstalled harness bridge. Its worker installs and reuses the exact harness version pinned by Mjolnir in the remote user’s cache. It does require Node.js 22 and npm for Codex, Claude, and DeepSeek, or curl and Bash for Kimi and Grok. Mjolnir never uses sudo to add these prerequisites and does not fall back to another harness executable from the remote PATH.

permissions is required and accepts guardian or yolo. SSH connection fields include identity_file and extra_args. See SSH and SSH Podman for host prerequisites, connection checks, and workspace cleanup.

All container targets require an image and accept optional pull_policy, platform, cpus, memory, and target environment. The published default is multi-architecture:

image = "ghcr.io/brokkai/mjolnir/agent-dev:latest"
pull_policy = "auto"

It carries the supported bridges and common development tools. A plain image can work, but every new session may need to install Git, GitHub CLI, Node, or a harness bridge. See Container targets and Custom images.

[targets.podman]
kind = "local-podman"
image = "ghcr.io/brokkai/mjolnir/agent-dev:latest"

Rootless Podman 4.0 or newer is the reference Linux/WSL2 runtime. It is the only runtime with configurable workspace backing: a named volume by default, the container layer, or a host path managed through an operator-supplied helper. See Podman.

[targets.docker]
kind = "local-docker"
image = "ghcr.io/brokkai/mjolnir/agent-dev:latest"

Docker requires a reachable Linux daemon. Mjolnir owns a managed volume for the session workspace and uses managed OverlayFS volumes for writable supplemental directories. Podman’s workspace_storage override is not accepted. See Docker.

[targets.apple]
kind = "apple-container"
image = "ghcr.io/brokkai/mjolnir/agent-dev:latest"
platform = "linux/arm64"

Apple’s container CLI requires Apple silicon and macOS 26 or newer. Supplemental directories are mounted read-only; writable OverlayFS views and Podman workspace-storage overrides are unavailable. See Apple container.

[targets.remote-podman]
kind = "ssh-podman"
host = "builder.example.com"
user = "ubuntu"
image = "ghcr.io/brokkai/mjolnir/agent-dev:latest"

This combines the SSH connection fields with every Podman container field. The container and any workspace volume live on the remote host. Supplemental directory sources are therefore paths on that remote host, not paths on the controller. See SSH and SSH Podman.

[targets.aws]
kind = "aws-ec2"
aws_profile = "default"
region = "eu-west-1"
launch_template = "lt-0123456789abcdef0"
ssh_user = "ubuntu"
address_source = "public-dns"

Mjolnir launches one instance per session from an existing launch template, discovers its configured public or private DNS/IP address, connects over SSH, and terminates it only after the recovery archive verifies. The launch template owns the AMI, networking, IAM, security groups, storage, and default instance type. The new-session wizard may select another allowed instance type for that session.

Supplemental controller-side directories are transferred as point-in-time snapshots. They are not live mounts and changes on the instance do not write back to the source directory. See AWS EC2 for the required AWS CLI, permissions, launch-template contract, and connectivity.

Managed targets—Podman, Docker, Apple Container, SSH Podman, and EC2—clone a configured bundle into a new session workspace. primary_repo is the agent’s working directory and every other repository is an additional ACP workspace root. GitHub repositories clone normally; controller-side local repositories use Mjolnir’s confined Git bridge.

Local and SSH bare sessions instead choose an existing project directory. Moving or resuming a stopped single-repository local session can convert between the bundle and bare representations when the destination supports it; a multi-repository bundle cannot become one checkout.

DeepSeek Harness supports one ACP workspace root, so it requires a single-repository bundle or one existing bare project directory, with no supplemental directories. See Workspaces and bundles for repository validation, dirty state, Git caching, and project memory.

The terminal new-session and resume flows can attach directories that are not part of the bundle. Each attachment has an absolute source, a unique safe absolute destination, and a read-only choice. The default destination is /mnt/<source-name>.

TargetSource locationWritable request
Local PodmanController hostPodman’s isolated overlay view.
Local DockerController hostManaged OverlayFS volume.
Apple ContainerController hostDowngraded to read-only.
SSH PodmanRemote container hostPodman’s isolated overlay view.
AWS EC2Controller hostSnapshot copy; no write-back.
Local/SSH bareUnsupported.

For Podman and Docker, NFS, SMB, FUSE, FAT-family, and existing overlay filesystems cannot safely host the requested overlay. Mjolnir detects these and forces the attachment read-only, reporting the reason. Sources must be absolute directory paths, and destinations must be unique safe absolute paths without parent traversal.

Attachments are per-session state in mj.sqlite3, not target fields in config.toml. They can be changed for the next recreation through F2 → Container settings where supported. See Session lifecycle.

Container target cpus and memory values are backend fallbacks for launch requests that do not supply a per-session allocation. The terminal wizard does not seed from them: it starts with the remembered size for that physical host or a baseline of 8 CPUs and 32 GiB, then clamps choices to known host limits. Its per-session choice overrides the fallback. Later Container settings overrides win when that session’s container is next created.

EC2 uses an instance type rather than independent CPU and memory strings. Bare targets use the host directly and have no Mjolnir resource limit.

These choices are capacity controls, not scheduling constraints. Mjolnir shows host and fleet usage but does not prevent overcommit.

Container pull_policy accepts:

ValueLaunch behavior
autoUse the existing image; pull when missing. Eligible moving tags are refreshed in the background for Podman, Docker, and SSH Podman. Apple resolves it during provisioning.
alwaysRefresh during launch.
newerRefresh when the runtime supports a newer-only check; Docker treats it as always.
missingPull only if absent.
neverNever pull; fail if absent.

Running containers are never replaced in place. A refreshed image is used by the next new or recreated session. Digest references remain pinned, versioned tags remain cached under auto, and local image names are not background refreshed.

Target environment versus profile environment

Section titled “Target environment versus profile environment”

For container targets, [targets.<id>.environment] becomes environment inside the target container. [profiles.<id>.environment] configures the harness and ACP bridge. AWS and bare target variants do not accept a target environment table, but profile environment still applies to their workers.

Do not put secrets in either table casually: config.toml is plain text. Use the harness login flow for provider credentials and the controller’s GitHub token flow for GitHub access. See Profiles and harnesses.

The examples above intentionally omit optional connection and storage fields. Use the Configuration reference for every accepted field, exact defaults, and validation constraints. Use Troubleshooting when a target appears configured but fails its doctor check or launch.