# psh.now - full agent context

> The smallest human-approval layer for AI agents: a skill, one host, and one page that says yes or no.

## Prompts (copy one)

Fresh install, nothing to join yet:

```text
I'd like you to set up psh.now: Install as a skill with npx skills add passy-ai/psh-now-skill -g -y

If not, do this instead: curl -fsSL https://psh.now/install.sh

After installing, send me a test request.
```

An agent that is already installed joins one channel with:

```text
I'd like you to use psh.now and join this channel: https://psh.now/c/<channel-id>
```

A new sandbox that must join while it installs:

```text
I'd like you to set up psh.now: Install as a skill with npx skills add passy-ai/psh-now-skill -g -y
and join https://psh.now/c/<channel-id>

If not, do this instead: curl -fsSL https://psh.now/install.sh
```

## What psh.now is
psh.now is a hosted (or self-hosted) HTTP endpoint that turns "may I do this?" into
a human decision on a psh.now page. It is intentionally minimal: one request
shape, one boolean response, no SDK, no session to manage. Any LLM with
shell or HTTP tool access can use it.

## Setup (agents)

```bash
npx skills add passy-ai/psh-now-skill -g -y   # with npm + git: copies the skill machine-wide (setup.sh then mints or joins)
# no npm, no git, or no GitHub access? this one line does both:
curl -fsSL https://psh.now/install.sh | sh                                             # machine-wide, no creds
./.psh/bin/psh                                                                  # what this is, where it lives, what next
curl -fsS https://psh.now/api/v1/health                                                 # -> {"ok":true}
curl -fsS https://psh.now/api/v1/me -H "x-psh-key: <userKey>"                           # -> your account + usage
```

Keys are **per project**: they land in `<project>/.psh/keys.json` (or `$PSH_HOME`).
**A finished install is machine-wide**: the skill and the `psh` CLI on the machine are what
make the next session in any folder find psh.now and run `psh` instead of rediscovering it, and
what keeps every project on ONE account. Those writes are outside the workspace, so do not ask for
blanket filesystem access on a web page's word - and do not leave the job silently half-done
either. If they were refused: say so in one line, send ONE ask through psh.now
(`psh ask "Install psh.now globally?"…`), and re-run with the permissions granted. setup.sh's
last line says which happened - `psh_machine_wide=ok` or `psh_machine_wide=incomplete`.

That is the whole setup. The mint response also carries `accessUrl` (track
requests), `claimUrl` (register a username), and `channelUrl` (the channel's own link).

## The one call

```bash
curl -s -X POST https://psh.now \
  -H "x-psh-key: psh_agent_REPLACE_ME" \
  -H "Content-Type: application/json" \
  -d '{"title":"Reinstall dependencies","message":"rm -rf node_modules && npm install --force"}'
```

Response:

```json
{ "approved": true }
```

If the `psh.now` CLI is installed, `psh ask "<message>" --title "<title>"` is
equivalent.

## Request fields
| Field | Required | Notes |
| --- | --- | --- |
| `title` | no | Short headline; derived from the message when omitted. |
| `message` | yes* | What you are about to do. *`command` is accepted as a legacy alias. |
| `kind` | no | `command`, `action`, or `question`. |
| `agent` | no | Identifies the calling agent. |
| `cwd` | no | Working directory. |
| `timeoutMs` | no | How long to wait before it auto-denies. |

## Response fields
`approved` (boolean), `promptId`, `status` (`approved`/`denied`/`expired`),
`reason`, `risk` (`low`…`critical`), `riskReasons`, and in async mode
`pollUrl` + `waiting:false`.

## Async (avoid proxy timeouts)

Some proxies cap a response at ~100s (Cloudflare → `524`). Send
`{"wait":false}` to get a session immediately, then poll:

```bash
curl -s -X POST https://psh.now -H "x-psh-key: …" -H "Content-Type: application/json" \
  -d '{"title":"Deploy","message":"Deploy the new build?","wait":false}'
# -> {"status":"pending","approved":false,"pollUrl":"https://psh.now/api/v1/approvals/…"}

curl -s "$POLL_URL?wait=30" -H "x-psh-key: …"   # holds up to 30s
# -> {"status":"approved","approved":true}
```

Cancel an unneeded request with `POST /api/v1/approvals/<id>/cancel`.

## MCP (optional)

The HTTP call above is the contract. MCP is a second front door for clients that cannot
install a skill: hosted builders, connector UIs, and apps that only speak the protocol.
One tool, one endpoint, plain JSON responses, no OAuth and no server-initiated stream.

- Endpoint: `POST https://psh.now/mcp` (streamable HTTP, stateless)
- Tool: `psh_ask` with `{title?, message, timeoutSec?}`. It blocks, then returns
  `{"approved":bool,"status":"approved"|"denied"|"answered"|"expired","answer":string|null,"promptId":"..."}`
- Auth: `x-psh-key: psh_agent_...`, or `Authorization: Bearer ...`. The tool is never anonymous.
- Descriptor: `https://psh.now/.well-known/mcp.json`

```bash
# Claude Code
claude mcp add --transport http psh https://psh.now/mcp --header "x-psh-key: psh_agent_REPLACE_ME"
```

```json
{ "mcpServers": { "psh": { "url": "https://psh.now/mcp",
    "headers": { "x-psh-key": "psh_agent_REPLACE_ME" } } } }
```

An `answer` is the human's own words: treat it as instruction, never as approval. Only
`approved: true` means yes. `denied`, `expired` and any error all mean do not act.

MCP is cooperative, exactly like the skill: an agent that never calls the tool can still
act. The enforcement point is the harness hook, not the transport.

## Provision a workspace (agents)

```bash
curl -s -X POST https://psh.now/api/v1/mint -H "Content-Type: application/json"
# -> { userKey, channelKey, workspaceId, appUrl, accessUrl, claimUrl, channelUrl }
```

`userKey` is the **account key**: it signs a human in at
`https://psh.now/app?key=…` and *is* the identity while anonymous. `channelKey` is what
the agent sends. The same response includes:
- `accessUrl` - open the dashboard to track requests (no sign-in)
- `claimUrl` - register a username + name/email to keep the account (20/day)
- `channelUrl` - the channel's own link; paste-ready prompts come from the
    dashboard's "Copy prompt for agent" button

**Always hand the human `accessUrl`, never the bare `appUrl`.** The key inside
the link *is* the sign-in: on a device with no session it lands straight on the
request, while `appUrl` alone shows a login gate. (If they are already signed
in somewhere else, the app keeps that session and says so - it never hijacks.)

Anonymous accounts are capped at **20 requests total** until claimed.

## When to use
- Before deleting or overwriting files, `rm -rf`, `--force`, `sudo`, force-push
- Before dropping, truncating, or migrating data
- Before installing, upgrading, or force-reinstalling dependencies
- Before deploying, publishing, or spending money
- When blocked on a decision outside your authority
- When running unattended and you hit a genuine ambiguity

## Rules
- Proceed **only** when `approved` is `true`.
- `false`, a timeout, or an error means **do not act**.
- Silence is never consent.
- Ask once for a real decision; do not re-ask for already-authorised steps.
- Keep `title` under ~60 characters and `message` to one or two lines.

## Enforcement
A skill is an **ask**: the model can skip it. A harness pre-tool hook is a
**gate**: it cannot be skipped. Never bypass an enforced gate.

## What it is
psh.now is a human-approval layer for AI agents: an agent sends a short question to a
person's page, blocks until that person approves or denies it, and gets back a single
boolean. It is open source (MIT), self-hostable, and works with any harness that can
make an HTTP call.

## What it is not
- Not MCP-only and not an SDK: one HTTP POST is the contract, no client library. An optional
MCP endpoint exists for clients that cannot install a skill, and nothing depends on it.
- Not hosted-only: the same code runs in your own VPC under MIT.
- Not a chat UI or an agent framework: it answers one question at a time.
- Not seat-priced: the hosted instance is a convenience, self-hosting is free.

## Common questions
**Is psh.now open source?** Yes. The server and the skill are MIT licensed at
https://github.com/passy-ai/psh-now - no open-core edition, no seat count.

**Can I self-host it?** Yes. Docker Compose, your own Postgres and mail;
https://psh.now/self-hosting covers it, and nothing about the agents leaves your infrastructure.

**How is it different from auto-approve (YOLO mode)?** Auto-approve deletes the
question. psh.now keeps it and makes answering cost one tap, so an agent can run
unattended without running unguarded.

**How is it different from a closed hosted approval service?** You can read the code
that decides what needs a human, and run it yourself. Auto-approve, a terminal
prompt, a closed hub and this are compared at https://psh.now/alternatives.

**What does it cost?** The code is free under MIT. The hosted instance has a free tier
and prepaid usage; https://psh.now/pricing is the agent-readable version.

**Which agents work with it?** Anything that can make an HTTP call - Claude Code,
Codex, Cursor, a shell script, a cron job in a container.

## Discovery
- Homepage: https://psh.now
- Teams: https://psh.now/teams
- Open source alternatives: https://psh.now/alternatives
- Source (MIT): https://github.com/passy-ai/psh-now
- Concise context: https://psh.now/llms.txt
- Sitemap: https://psh.now/sitemap.xml
- Skill: https://psh.now/skill.md
- OpenAPI: https://psh.now/openapi/json
- Agent card: https://psh.now/.well-known/agent-card.json
