Skip to content

Design: run session payloads as local agent OS users #73

Description

@ikma-ricon

Summary

Add first-class support for waking a session whose payload runs as a local agent OS user, while keeping the shell/zmx session owned by the caller.

This is for the Iris onboarding lane: Iris has a macOS user, but agent harness execution still runs as the human/caller user. We need a clean boundary before continuing Iris gh auth, repo publication, or commits.

Boundary decision

shell and zmx stay caller-owned. sessions owns OS-user orchestration.

Desired stack:

rikonor
  sessions wake
    shell run <session-name>
      zmx session owned by rikonor
        sessions/libexec/run-as-user --user iris -- <sessions run ...>
          sessions run / harness payload as iris

So:

  • shell does not get --user.
  • zmx does not run as the agent user.
  • Only the payload command inside the zmx session runs as the target OS user.
  • Session ownership/list/status/attach/send/kill remain with the caller that started the session.

Proposed user-facing surface

sessions wake <session> --os-user iris --message "..."

Also support defaulting from:

SHIMMER_OS_USER=iris

Precedence:

  1. explicit --os-user
  2. $SHIMMER_OS_USER
  3. unset = current behavior

Wake events should record the target OS user, probably top-level:

{"type":"wake", "os_user":"iris", ...}

Internal run-as helper

Add an internal executable, not a mise task:

libexec/run-as-user

Contract:

libexec/run-as-user --user iris -- <cmd...>

Initial implementation should be intentionally boring:

  • validate CLI shape
  • validate username syntax
  • optionally provide friendly checks/errors for target group membership
  • use sudo as the permission authority
  • execute with an explicit target environment, not inherited caller env

Sketch:

sudo -n -H -u "$user" -- \
  env -i \
    HOME="$target_home" \
    USER="$user" \
    LOGNAME="$user" \
    SHELL="$target_shell" \
    PATH="$controlled_path" \
    "$@"

Open question: exact controlled PATH. Initial candidate:

$HOME/.local/bin:$HOME/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

We should not inherit the invoking user environment by default.

Host policy model

Use sudoers and Unix groups first; do not introduce a custom permission system yet.

Initial local-machine model:

  • humans group: trusted human OS users
  • agents group: local agent OS users
  • members of humans may run commands as members of agents without password

Conceptual sudoers rule:

%humans ALL=(%agents) NOPASSWD: ALL

This means:

  • humans → agents: allowed
  • agents → humans: not allowed
  • agents → agents: not allowed unless separately granted

run-as-user is convenience + environment control; sudoers is the security boundary.

Host setup commands

Add host support in sessions, initially as mise tasks or CLI-backed tasks:

sessions host:doctor --os-user iris
sessions host:fix --os-user iris --dry-run
sessions host:fix --os-user iris

Responsibilities:

  • check/create humans
  • check/create agents
  • ensure current human is in humans
  • ensure target agent is in agents
  • install/validate sudoers drop-in
  • validate with visudo -c
  • smoke-test:
    libexec/run-as-user --user iris -- whoami

host:fix --dry-run should print exact commands/files it would apply. Normal sessions wake must never mutate host policy.

Suggested PR split

PR 1: runtime primitive + host diagnostics

  • Add libexec/run-as-user.
  • Add host:doctor.
  • Add host:fix --dry-run.
  • Consider making mutating host:fix print a clear "not implemented yet" until the dry-run surface is reviewed.
  • Tests use fake sudo/fake host commands; no real host mutation in tests.

PR 2: wake integration

  • Add sessions wake --os-user <user>.
  • Add $SHIMMER_OS_USER fallback.
  • Record os_user on wake events.
  • Wrap RUN_CMD with libexec/run-as-user --user "$OS_USER" -- ... before invoking shell run or foreground exec.
  • Tests mock the wrapper and assert command construction.

Current local probe

On Or's machine as of 2026-05-10:

  • agents group exists and contains iris.
  • humans group does not exist.
  • iris exists and is in agents.
  • sudo -n -H -u iris -- ... currently fails with sudo: a password is required.

So host policy setup is required before an Iris smoke test can pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions