README.md
Rama master · réplica de lectura del repositorio original.
# Palmier
[](https://github.com/caihongxu/palmier/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/palmier)
[](https://github.com/caihongxu/palmier/blob/master/LICENSE)
**Website:** [palmier.me](https://www.palmier.me) | **Web App:** [app.palmier.me](https://app.palmier.me) | **Android App:** [caihongxu/palmier-android](https://github.com/caihongxu/palmier-android)
Palmier installs, manages, and runs AI agent CLIs (Claude Code, Codex, GitHub Copilot, etc.) on your machine using your existing AI subscriptions, and exposes them to your phone through a mobile-friendly PWA and an Android app. It runs as a background daemon and is agent-agnostic — adding support for a new CLI is a config change, not a code change.
The control surface is bidirectional:
* **Phone → agents:** start ad-hoc sessions, register schedule- or event-triggered tasks, inspect session output, and respond to agent input/confirmation requests.
* **Agents → phone:** agents can read device state (location, calendar, contacts, notifications, SMS, battery) and trigger actions (push notifications, full-screen alarms, SMS, email, contact/calendar writes, ringer mode).
Capability access is opt-in per device: each capability is gated behind an Android permission and a per-host toggle. Agents always run in yolo mode (all tool calls auto-approved) when their CLI supports it.
## Quick Start
1. Install Palmier and run setup:
**Linux / macOS:**
```bash
curl -fsSL https://palmier.me/install.sh | bash
```
**Windows:**
```powershell
powershell -c "irm https://palmier.me/install.ps1 | iex"
```
The one-liner installs Node.js 24+ if needed, installs `palmier` globally, and runs the setup wizard. On Windows it also sets the PowerShell execution policy to `RemoteSigned` for the current user if scripts are blocked, since npm's `palmier.ps1` shim can't run otherwise. If you already have Node.js 24+ and npm:
```bash
npm install -g palmier && palmier init
```
The wizard creates `~/palmier` as the task storage directory, detects existing agent CLIs or offers to install supported ones ([Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Codex CLI](https://github.com/openai/codex), [GitHub Copilot](https://github.com/github/gh-copilot), [OpenClaw](https://openclaw.ai/), or [others](https://www.palmier.me/agents)), configures access, installs the background daemon, and starts pairing.
2. Open `http://localhost:7256` to access the app locally — no pairing needed.
3. To access from other devices, enter the pairing code shown after init into the [PWA](https://app.palmier.me) or the [Android app](https://github.com/caihongxu/palmier-android/releases/latest/download/palmier.apk).
### Prerequisites
- **Linux with systemd**, **macOS 13+**, or **Windows 10/11**
## How It Works
Palmier runs as a background daemon (systemd on Linux, launchd on macOS, Task Scheduler on Windows). It invokes your agent CLIs directly, schedules tasks via native OS timers, and exposes an API that the PWA connects to — either directly over HTTP or remotely through a relay server. Agents can interact with the user's mobile device during execution — requesting input, sending push notifications and full-screen alarms, reading SMS/notifications, managing contacts and calendar, and more.
### Agent Capabilities
Every task Palmier runs gets these capabilities automatically. Their usage is written into the agent's instructions at launch, so no agent-side setup is needed.
**Actions:**
| Capability | Description |
|------------|-------------|
| `notify` | Send a push notification to the user's device |
| `fill-password` | Fill a saved password or PIN into the active browser session and submit the form, prompting the user if unknown (the secret is never revealed to the agent) |
| `device-geolocation` | Get GPS location of the user's mobile device |
| `read-contacts` | Read the contact list from the user's device |
| `create-contact` | Create a new contact on the user's device |
| `read-calendar` | Read calendar events (with time range filter) |
| `create-calendar-event` | Create a calendar event on the user's device |
| `send-sms-message` | Send an SMS message from the user's device |
| `send-email` | Send an email from the user's device (opens the email app with the draft pre-filled for review) |
| `send-alarm` | Trigger a full-screen alarm popup with ringtone on the user's device (pierces DND) |
| `read-battery` | Get battery level and charging status |
| `set-ringer-mode` | Set ringer mode (normal/vibrate/silent) |
**Device data:**
| Capability | Description |
|------------|-------------|
| Device Notifications | Recent notifications from the user's Android device |
| Device SMS | Recent SMS messages from the user's Android device |
All device tools work while the Palmier Android app is in the background — they communicate via FCM data messages which wake the app's service even when it's not in the foreground. Each host has one **linked device**: the phone the host uses for SMS, contacts, location, and other device capabilities. Choose it at pair time (the "Link the host to this device" checkbox) or later from the drawer. Each capability must be enabled and its Android permission granted via toggles in the linked device's drawer.
### Instructions for All Tasks
Each host can have one standing prompt, set from **Instructions** in the app's side panel. It's stored in `host.json` and added to the agent's instructions at launch, ahead of the task description, so it applies to every run on that host, including scheduled and event-triggered ones. Edits take effect on the next run; a follow-up continues a session that already has the earlier text.
### Asking the User
When an agent needs something from the user, it writes its question as its final message and ends with the `[PALMIER_TASK_NEED_INPUT]` marker. The agent CLI then exits and the run moves to a "needs input" state, with a push notification that opens the run. The user answers in the run view's message box, or aborts from there.
`palmier run` stays alive during the wait, so anything the agent left running, such as its browser, stays open. Palmier polls for the reply and resumes the same agent session with it, repeating until the agent reports success or failure. An unanswered question fails the run after 24 hours. The reply is handed over through a file in the run directory, so a daemon restart doesn't lose the wait.
### Files in Agent Output
Agents run with the task's run directory (`~/palmier/tasks/<task-id>/<run-id>/`) as their working directory and are instructed to link any file they produce with a relative markdown link, e.g. `[View report](report.md)` or ``. The app opens these links over whichever transport is in use (local, relay, or auto-LAN). It fetches the file through the `task.file` RPC in 512 KiB chunks, so large files fit within the relay's message size. Markdown files render in-app, with their own relative links and images resolved from the file's location. Text and images are previewed, and other file types are offered as a browser download. The host only serves files whose real path (after resolving symlinks) is inside that task's directory, up to 25 MB. A run whose output links an existing file triggers a "report ready" push notification.
### Architecture
```
┌──────────────┐ HTTP ┌──────────────────┐
│ │◄──────────────────────│ │
│ Host Daemon │ │ PWA (Browser) │
│ │◄──────┐ │ │
└──┬────────┬──┘ │ └──────────────────┘
│ │ │ │
▼ ▼ │ NATS (TLS) │ NATS (TLS)
┌──────┐ ┌──────┐ │ ┌────────┴─────────┐
│Agent │ │Agent │ └───────────────│ Relay Server │
│ CLIs │ │Tools/│ │ (passthrough, │
│ │ │Rsrcs │◄──── FCM ───────────│ push, FCM) │
└──────┘ └──────┘ └──────────────────┘
│
FCM │
▼
┌──────────────────┐
│ Android Device │
│ (notifications, │
│ SMS, contacts, │
│ calendar, GPS) │
└──────────────────┘
Local mode (loopback): direct HTTP on the host machine
Server mode: via relay (events) + auto-LAN direct HTTP for RPC when reachable (native app)
```
## Access Modes
Three ways to reach your host, ordered by setup effort:
| Mode | Where | Pairing | Notes |
|------|-------|---------|-------|
| **Local (browser)** | `http://localhost:7256` in a browser on the host machine | Not required | Loopback only. No internet or Palmier server connection needed. |
| **PWA** | [https://app.palmier.me](https://app.palmier.me) in any browser | Required | Installable to your home screen; supports web push notifications. Always goes through the cloud relay. |
| **Android app** | [Android APK](https://github.com/caihongxu/palmier-android/releases/latest/download/palmier.apk) | Required | Unlocks phone capabilities (GPS, email, calendar, contacts, SMS, alarms), push notifications, and **auto-LAN**. |
iOS app coming soon.
**Auto-LAN (native app only).** When the Android app is on the same network as the host, it transparently routes RPC over direct LAN HTTP (`http://<host-ip>:7256/rpc/...`) instead of through the relay — lower latency, no protocol change. Browser PWAs can't do this (Private Network Access / mixed-content restrictions) and stay on the relay.
## Security & Privacy
**Local mode** — all traffic stays on `127.0.0.1`. No data leaves your machine. The web UI, `/pair`, and `/events` reject any non-loopback caller; only `/rpc/<method>` (bearer-auth) and `/health` are reachable from the LAN.
**Server mode** — communication between your device and host is relayed through the Palmier cloud server over TLS-encrypted NATS connections. The server acts as a passthrough relay only — it does not store, log, or inspect any user data, task content, or agent output. The only data the server persists is a host registration ID used for message routing and push subscription tokens for delivering notifications. See the [Privacy Policy](https://www.palmier.me/privacy) for full details.
**Auto-LAN** — direct LAN HTTP requests use the same client token (Bearer auth) generated during pairing. The host validates every `/rpc/*` call regardless of source.
In all modes, client tokens are generated and validated entirely on your host. The Palmier server never sees or stores them.
## Setup Details
### Pairing Devices
Local access (`http://localhost:7256`) works immediately — no pairing needed.
For remote access (web or app), run `palmier pair` on the host to generate a code, then enter it at [https://app.palmier.me](https://app.palmier.me) or in the Android app. Pairing always goes through the relay; auto-LAN kicks in transparently afterward in the native app when on the same network.
### Managing Clients
```bash
# List all paired devices
palmier clients list
# Revoke a specific device's access
palmier clients revoke <token>
# Revoke all clients (unpair all devices)
palmier clients revoke-all
```
Revoking the linked device also clears the host's linked-device record; device capabilities stop working until another paired device is linked from its drawer.
### Saved Passwords
Palmier can store website passwords and PINs like a browser's password manager so agents can sign in to sites without ever seeing the credentials. When an agent driving a browser (via the `playwright-cli` skill) reaches a login or PIN field, it calls the `fill-password` tool with the page URL, the username, and the field's element ref. Palmier matches the saved secret by **origin**, fills it directly into the live browser session, and presses Enter to submit the form in the same step — so the plaintext secret sits on the page for as little time as possible and never enters the agent's context. If nothing is saved for that `(origin, username)`, Palmier prompts you in the app with a masked dialog. The dialog has a "Save for next time" checkbox (on by default): leave it checked to store the secret for reuse, or uncheck it to fill it just this once without saving. Either way it is filled into the page. The plaintext secret is never returned to the agent and is never written to task history.
Saved passwords and PINs are encrypted at rest with AES-256-GCM under a host-local key, both stored in `~/.config/palmier/` (`passwords.enc` and `password-key`). Manage them from the app via **Manage saved passwords** in the side panel (lists origin and username only, with per-entry delete).
### The `init` Command
The wizard:
- Detects installed agent CLIs and caches the result; agents previously installed by Palmier have their installed version re-probed so the recorded version stays in sync with manual upgrades
- Offers to install missing supported agents from npm (one at a time, arrow-key menu). After each install the agent's version is stamped (becoming "Palmier-managed"), the wizard kicks off authentication, and waits for you to press Enter before offering the next install. On re-init, the agents list is saved after every install so an interrupted wizard is resumable.
- Offers to install the **Playwright CLI** for browser automation (see [Browser Automation](#browser-automation)). Skipped on re-init if it's already managed.
- Asks for the HTTP port
- Detects the default network interface (used for auto-LAN)
- Shows a summary (including the Palmier daemon version and any existing scheduled tasks to recover) and asks for confirmation
- Registers with the Palmier server, saves configuration to `~/.config/palmier/host.json`
- Installs a background daemon (systemd user service on Linux, LaunchAgent on macOS, Task Scheduler on Windows). On re-init, also restarts the daemon so the running process picks up the new agents/versions for `host.info`.
- Auto-enters pair mode to connect your first device
The daemon automatically recovers existing tasks by reinstalling their system timers on startup.
> **macOS note:** Palmier installs as a user-level LaunchAgent, so it runs without `sudo`. LaunchAgents only run while the user is logged into the GUI session — after a reboot, scheduled tasks stay dormant until you log in at least once. Enable auto-login in System Settings → Users & Groups if you need unattended operation across reboots.
Agents are re-detected on every daemon start; managed-agent versions are re-probed live so upgrades performed outside the wizard show up automatically.
### Palmier-managed Agents
An agent is considered **Palmier-managed** if it was installed via `palmier init`, `palmier agents`, or its update is initiated via the PWA. Palmier-managed agents have a known installed version stamped at install/update time; that version is what the PWA uses to drive the agent soft-update dialog and what's recorded into each session's run metadata so a session always shows the agent version it actually ran with — even after the live agent is upgraded.
Agents installed by the user outside the wizard (e.g., `npm install -g <pkg>` directly) are detected and usable but are **not** considered Palmier-managed. The PWA shows them under a separate "Version not managed by Palmier" section and does not offer auto-update for them.
Run `palmier agents` to manage agent CLIs after setup: it lists installed agents and offers an interactive picker to install or uninstall one. `palmier init` only prompts for an agent install when none are detected; once any agent is installed, init just lists them and continues with host registration.
### Browser Automation
Some capabilities (like the [saved-password autofill](#saved-passwords)) drive a real browser through the [`playwright-cli`](https://www.npmjs.com/package/@playwright/cli) skill. `palmier init` offers to install and manage the Playwright CLI (`@playwright/cli`) for this, and on install also runs `playwright-cli install --skills` in your Palmier task directory (`~/palmier`) so agents get the Playwright skills that teach them how to drive the browser. When you opt in, Palmier manages it **just like an agent CLI** — the version is stamped, re-probed live on each daemon start, and the PWA shows a "Browser Automation Update Available" dialog (same flow as agents) when a newer version is published. Its version is shown in the app's host drawer. The browser binaries Playwright needs are downloaded lazily on first use, not during init.
Unlike agents, the Playwright CLI has **no explicit uninstall** — it's not offered in any uninstall picker. It is removed only by a full `palmier uninstall`.
### Updates
- **Palmier itself** — when a newer version of `palmier` is published to npm, the PWA shows an "Update Available" dialog. Clicking "Update Now" runs `npm update -g palmier` on the host and restarts the daemon. Clicking "Dismiss" only hides it for the current session — reopening or reloading the app shows it again until you update.
- **Palmier-managed agents** — same flow per agent: when npm publishes a newer version, the PWA shows an "Agent Update Available" dialog. Clicking "Update Now" runs `npm update -g <pkg>` on the host (no daemon restart needed).
- **Managed Playwright CLI** — same flow: a "Browser Automation Update Available" dialog runs `npm update -g @playwright/cli`.
Dismissals are session-only: they are never persisted, so a reload re-arms every update dialog until the update is applied.
### Re-detecting the LAN Network
The default network interface is detected once during `palmier init` and saved to `host.json`. The daemon derives the current IP live from that interface on each client connect, so DHCP-assigned IP changes on the same adapter are picked up automatically. If you physically switch to a different network adapter (e.g., plug in Ethernet after running on WiFi, or add a new USB-tethered interface), run `palmier init` again to re-detect.
## CLI Reference
| Command | Description |
|---|---|
| `palmier init` | Interactive setup wizard |
| `palmier agents` | List, install, and uninstall agent CLIs |
| `palmier pair` | Generate a pairing code to pair a new device |
| `palmier clients list` | List active client tokens |
| `palmier clients revoke <token>` | Revoke a specific client token |
| `palmier clients revoke-all` | Revoke all client tokens |
| `palmier info` | Show host connection info (address, mode) |
| `palmier serve` | Run the persistent RPC handler (default command) |
| `palmier restart` | Restart the palmier serve daemon |
| `palmier run <task-id>` | Execute a specific task |
| `palmier uninstall` | Stop daemon, remove all scheduled tasks, and uninstall Palmier-managed agent CLIs and the managed Playwright CLI |
## Uninstalling
To fully remove Palmier from a machine:
1. **Unpair your device** in the PWA (via the host menu).
2. **Stop the daemon, remove all scheduled tasks, and uninstall Palmier-managed agent CLIs and the managed Playwright CLI:**
```bash
palmier uninstall
```
Agents you installed yourself outside Palmier (no managed version stamp) are left in place.
3. **Uninstall the package:**
```bash
npm uninstall -g palmier
```
4. **(Optional) Remove configuration and task data:**
**Linux / macOS:**
```bash
rm -rf ~/.config/palmier
rm -rf ~/palmier # or wherever your Palmier root directory is
```
**Windows (PowerShell):**
```powershell
Remove-Item -Recurse -Force "$env:USERPROFILE\.config\palmier"
Remove-Item -Recurse -Force "$env:USERPROFILE\palmier" # or wherever your Palmier root directory is
```
## Disclaimer
Palmier spawns AI agents that can read, write, and execute on your machine. [Read the full disclaimer](DISCLAIMER.md) before use. By using Palmier, you agree to the [Terms of Service](https://www.palmier.me/terms) and [Privacy Policy](https://www.palmier.me/privacy).
## License
This project is licensed under the Apache License 2.0. See [LICENSE](LICENSE) for the full text.