Summary
CreatePuffer (and puffer daemon startup) fails with the following error even when the caller explicitly requested no_browser: true:
ERROR: Internal
Message: agent-browser skill source missing at /opt/tintin/agent-browser/SKILL.md while Browser is denied
The error message itself acknowledges that Browser is denied yet still requires the skill file to be present. That's contradictory and makes deploying puffer outside of the canonical container image painful, because puffer pulls the agent-browser skill from a hard-coded absolute path (/opt/tintin/agent-browser/SKILL.md) regardless of the caller's permission posture.
Repro
On a host without the canonical /opt/tintin/agent-browser/ layout, with a recent puffer binary:
# manager forks puffer daemon with --no-browser
puffer-manager --listen-addr 0.0.0.0:18051 \
--puffer-bin /path/to/puffer ...
grpcurl -d '{
"puffer_id": "test",
...
"no_browser": true
}' 127.0.0.1:18051 tintin.puffer_manager.PufferManager/CreatePuffer
Returns gRPC Internal with the error above. The same call succeeds once a stub SKILL.md is placed at the expected path.
We worked around this by copying any agent-browser SKILL.md from a local npm cache into /opt/tintin/agent-browser/SKILL.md, but a stub being mandatory is the wrong contract for no_browser=true runtimes.
Expected behavior
If the runtime is configured with no_browser=true (or equivalently, browser is denied by the runtime permission profile), puffer should:
- Skip loading the agent-browser skill entirely
- Not check that the SKILL.md exists
- Surface a clean, structured error if loading is required for some unrelated reason (so callers don't have to grep the message)
Suggested fix
Gate the existence-check on the same browser_allowed flag the rest of the code uses to populate the runtime capabilities. The capabilities response correctly reports the disabled state already:
"capabilities": {
"browserAgentBridge": true,
"browserMode": "agentenv",
"blocker": "Puffer is launched with --no-browser by managed-agent; ..."
}
So the manager knows the browser path is off — the SKILL.md check should respect that.
Severity
P2. Doesn't block deployments that ship the canonical container, but adds friction for anyone running puffer on a host that wasn't provisioned through that container (test stacks, dev machines, alternative deployment shapes).
Summary
CreatePuffer(andpuffer daemonstartup) fails with the following error even when the caller explicitly requestedno_browser: true:The error message itself acknowledges that Browser is denied yet still requires the skill file to be present. That's contradictory and makes deploying puffer outside of the canonical container image painful, because puffer pulls the agent-browser skill from a hard-coded absolute path (
/opt/tintin/agent-browser/SKILL.md) regardless of the caller's permission posture.Repro
On a host without the canonical
/opt/tintin/agent-browser/layout, with a recent puffer binary:Returns gRPC
Internalwith the error above. The same call succeeds once a stubSKILL.mdis placed at the expected path.We worked around this by copying any agent-browser
SKILL.mdfrom a local npm cache into/opt/tintin/agent-browser/SKILL.md, but a stub being mandatory is the wrong contract forno_browser=trueruntimes.Expected behavior
If the runtime is configured with
no_browser=true(or equivalently, browser is denied by the runtime permission profile), puffer should:Suggested fix
Gate the existence-check on the same
browser_allowedflag the rest of the code uses to populate the runtime capabilities. The capabilities response correctly reports the disabled state already:So the manager knows the browser path is off — the SKILL.md check should respect that.
Severity
P2. Doesn't block deployments that ship the canonical container, but adds friction for anyone running puffer on a host that wasn't provisioned through that container (test stacks, dev machines, alternative deployment shapes).