Devcontainers

AI agents inside devcontainers need access to issue trackers, Notion, Figma, and Amplitude, but credentials should stay on the host. human solves this with a daemon that forwards CLI commands from the container to the host.

Architecture

[Devcontainer]                          [Host]
human jira issues list                  human daemon (:19285)
    |  TCP                                  |  (executes command with
    └───── :19285 ──────────────────────────┘    host credentials)

The daemon also runs a chrome proxy on :19286 for Chrome Bridge support, an HTTPS proxy on :19287 for outbound traffic filtering, and a FUSE .env filter that hides secrets from the agent.

Install human inside devcontainers using the treehouse devcontainer Feature.

Host setup

human daemon start

Output:

Token: a1b2c3...
Token file: ~/.human/daemon-token
Listening on: :19285
Chrome proxy on: :19286
HTTPS proxy on: :19287
FUSE .env filter: /home/you/project-sec

Run in the container:
  export HUMAN_DAEMON_ADDR=192.168.1.5:19285 HUMAN_DAEMON_TOKEN=a1b2c3... HUMAN_CHROME_ADDR=192.168.1.5:19286 HUMAN_PROXY_ADDR=192.168.1.5:19287

Container setup

In your devcontainer.json, add the treehouse devcontainer Feature:

{
  "features": {
    "ghcr.io/stephanschmidt/treehouse/human:1": {}
  },
  "forwardPorts": [19285, 19286],
  "remoteEnv": {
    "HUMAN_DAEMON_ADDR": "localhost:19285",
    "HUMAN_DAEMON_TOKEN": "a1b2c3...",
    "HUMAN_CHROME_ADDR": "localhost:19286"
  }
}

A ready-to-use example is available in the treehouse test-devcontainer.

Usage

Inside the container, all commands work transparently:

human jira issues list --project=KAN
human notion search "quarterly report"
human figma file get ABC123

The daemon handles authentication and API calls on the host.

Security

HTTPS proxy

The daemon includes a transparent HTTPS proxy on port 19287 that filters outbound traffic from devcontainers by domain. It reads the SNI from TLS ClientHello — no certificates needed, no traffic decryption.

Configure allowed domains in .humanconfig.yaml on the host:

proxy:
  mode: allowlist    # or "blocklist"
  domains:
    - "*.github.com"
    - "api.openai.com"
    - "registry.npmjs.org"
Mode Behavior
allowlist Only listed domains pass, everything else blocked
blocklist Only listed domains blocked, everything else passes
No proxy: section Block all (safe default)

Wildcard *.example.com matches subdomains but not example.com itself.

Enable in devcontainer.json using the treehouse Feature:

{
  "features": {
    "ghcr.io/stephanschmidt/treehouse/human:1": {
      "proxy": true
    },
    "ghcr.io/anthropics/devcontainer-features/claude-code:1": {}
  },
  "capAdd": ["NET_ADMIN"],
  "forwardPorts": [19285, 19286],
  "remoteEnv": {
    "HUMAN_DAEMON_ADDR": "localhost:19285",
    "HUMAN_DAEMON_TOKEN": "a1b2c3...",
    "HUMAN_CHROME_ADDR": "localhost:19286",
    "HUMAN_PROXY_ADDR": "${localEnv:HUMAN_PROXY_ADDR}"
  },
  "postStartCommand": "sudo human-proxy-setup && human install --agent claude"
}

The proxy: true option installs iptables and the human-proxy-setup script at image build time. At container start, the script reads HUMAN_PROXY_ADDR and sets up the iptables redirect. If the variable is unset, the script skips gracefully.

.env file protection

The daemon creates a FUSE mount at <project>-sec/ that mirrors your workspace. The container mounts this filtered view instead of the real directory. Regular files pass through at native speed. .env files appear in directory listings but return empty content when read. Writes to .env files are blocked with a read-only filesystem error.

Protected patterns: .env, .env.local, .env.production, .env.* — any file starting with .env in any directory.

No container changes needed. No SYS_ADMIN, no /dev/fuse, no FUSE packages. The FUSE daemon runs entirely on the host. If FUSE is not available, the daemon logs a warning and continues without .env protection.

See the .env Secret Protection feature page for details.

Environment variables

Variable Description
HUMAN_DAEMON_ADDR Daemon address (e.g. localhost:19285)
HUMAN_DAEMON_TOKEN Authentication token
HUMAN_CHROME_ADDR Chrome proxy address (e.g. localhost:19286)
HUMAN_PROXY_ADDR HTTPS proxy address (e.g. 192.168.1.5:19287). Printed by human daemon start.

Daemon commands

human daemon start             # Start the daemon
human daemon start --addr :8080  # Start on a custom port
human daemon token             # Print the current token
human daemon status            # Check if a daemon is reachable
human daemon status --addr host:port  # Check a specific address