04
Use your existing tools
- Keep the MCP servers, skills, permissions, and integrations already configured in Claude Code, Codex, or Pi.
+ Keep the MCP servers, skills, and integrations already configured in Claude Code, Codex, or Pi. Chats also preserve your configured permissions.
@@ -99,7 +99,9 @@ sends the result back when the work is done.
Push does not replace your coding agent. It handles chat, history, schedules,
approvals, and delivery. Claude Code, Codex, or Pi keeps control of models,
-tools, skills, permissions, and authentication.
+tools, skills, and authentication. Chats preserve configured agent permissions;
+Codex and Claude jobs bypass interactive permissions so scheduled work can
+finish without an operator.
[See the full architecture](architecture.md){ .push-inline-link }
diff --git a/docs/jobs.md b/docs/jobs.md
index c7c09f9..258df27 100644
--- a/docs/jobs.md
+++ b/docs/jobs.md
@@ -171,7 +171,8 @@ and primary delivery destination.
## Execution and delivery guarantees
- Every job and evaluator run uses a fresh backend session, without chat history.
-- Jobs use the selected agent's own permission configuration.
+- Codex and Claude jobs bypass interactive permissions so unattended work can
+ complete. Evaluators remain restricted.
- Push does not retry failed or timed-out backend execution because the agent
may have completed external side effects before failing.
- Success, failure, timeout, overlap, and delivery state are stored separately.
@@ -209,6 +210,7 @@ job. Rejection leaves the proposal inactive.
!!! warning
- Jobs use the selected agent's own permissions. A headless backend may not
- ask for approval interactively, so configure its
- unattended permissions carefully and keep job work directories narrow.
+ Jobs have no interactive approval path. Push runs Codex jobs with full
+ access and no prompts and Claude jobs in `bypassPermissions` mode. Treat
+ every enabled job as code execution by the Push service user, keep job work
+ directories narrow, and allow only trusted senders and job definitions.
diff --git a/docs/jobs/design.md b/docs/jobs/design.md
index 8b2470c..f645fbe 100644
--- a/docs/jobs/design.md
+++ b/docs/jobs/design.md
@@ -47,8 +47,9 @@ an agent runtime.
- Push has one long-running gateway process with no inbound server port.
Commands may run as short-lived local processes against the same SQLite
store.
-- Claude Code, Codex, and Pi own their permission controls. Push passes no
- permission or tool overrides.
+- Chats use the selected agent's permission controls without overrides. Codex
+ and Claude jobs bypass interactive permissions so unattended runs can finish;
+ Pi has no native filesystem sandbox or approval prompt.
- Scheduled work can have external side effects, so duplicate execution is more
dangerous than skipping a missed run.
- Job files, `SOUL.md`, and `context/` belong to the Git-versioned assistant
@@ -143,8 +144,9 @@ A scheduled occurrence is cancelled if its trigger no longer exists in that
validated snapshot. Immediately before spawning a backend, Push resolves the
work directory again so a path replacement is likely to be detected. This
path-based check does not eliminate a replacement race between validation and
-child startup; the agent's configuration and OS permissions remain the
-enforcement boundary. The timeout must not exceed the configured jobs maximum.
+child startup. Jobs bypass interactive backend permissions, so OS permissions
+remain the enforcement boundary. The timeout must not exceed the configured
+jobs maximum.
Notification behavior follows the trigger rather than job metadata. A manual
run prints its result to the invoking terminal and does not send a message. A
diff --git a/docs/security.md b/docs/security.md
index 85b74ea..46195b9 100644
--- a/docs/security.md
+++ b/docs/security.md
@@ -24,8 +24,8 @@ Slack allowlists use stable member IDs, never mutable display names.
## Agent permissions
Push does not pass sandbox, approval-policy, permission-mode, or tool-list
-overrides to Claude Code, Codex, or Pi. The selected agent's own configuration
-is the sole permission source for chats and jobs.
+overrides for chats. The selected agent's own configuration is the permission
+source for chat requests.
This makes Push behave like the agent you already configured, but it also means
every agent-approved capability may be one accepted message away. Review the
@@ -40,9 +40,17 @@ selected agent instead.
## Job permissions
-Jobs use the selected agent's own permission configuration. Push requires a
-fixed, existing work directory and rejects overlap with Push-owned files,
-including the loaded config file.
+Jobs must complete without an interactive approval channel. Push therefore runs
+Codex jobs with full filesystem and network access and no approval prompts, and
+runs Claude jobs in `bypassPermissions` mode. Pi already has no native
+filesystem sandbox or interactive permission prompt. Evaluators remain
+read-only with tools disabled.
+
+This makes job bodies equivalent to unattended code execution as the Push
+service user. Push requires a fixed, existing work directory and rejects overlap
+with Push-owned files, including the loaded config file. Keep allowed senders
+and job definitions trusted, and run the service with only the OS permissions
+its jobs require.
Do not place secrets in a job body. Make them available through the backend or
service environment using the narrowest policy that works.
diff --git a/docs/services.md b/docs/services.md
index d9af03e..f0d0aac 100644
--- a/docs/services.md
+++ b/docs/services.md
@@ -237,8 +237,9 @@ is completed.
Managed services run without a person watching the terminal. An allowed sender
can instruct the configured backend to use its tools, subject to your backend
settings. Keep `imessage.allow_from` narrow and configure each selected agent
-for unattended use. Push passes no sandbox, approval, or tool overrides. Jobs
-are kept away from Push-owned paths by work-directory validation.
+for unattended use. Push preserves backend permissions for chats. Codex and
+Claude jobs bypass interactive permissions so they can finish without an
+operator. Jobs are kept away from Push-owned paths by work-directory validation.
Store config files, state files, audit logs, backend credentials, and service
logs with permissions appropriate for the service user. Logs may contain
diff --git a/src/agent.rs b/src/agent.rs
index 765bfb3..7982ad6 100644
--- a/src/agent.rs
+++ b/src/agent.rs
@@ -131,6 +131,20 @@ impl Runner {
}
}
+ pub async fn run_unattended(
+ &self,
+ req: Request<'_>,
+ timeout: Duration,
+ ) -> Result