You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: plugins/remote-cli/skills/remote-cli/SKILL.md
+82-3Lines changed: 82 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
---
2
2
name: remote-cli
3
-
description: Use when the user asks you to perform any Remote.com HR action — create or list time off, manage expenses (approve/decline/download receipts), list or create employments, download payslips, submit terminations — via the remotecli CLI tool in this project. Also triggers when asked to look up leave balance, employment status, or company info through the CLI.
3
+
description: Use when the user asks you to perform any Remote.com HR action — create or list time off, manage expenses (approve/decline/download receipts), list or create employments, view or amend employment contracts (salary changes, title changes, etc.), download payslips, submit terminations — via the remotecli CLI tool in this project. Also triggers when asked to look up leave balance, employment status, or company info through the CLI.
4
4
---
5
5
6
6
# Using the Remote CLI
@@ -22,9 +22,65 @@ remotecli companies list # see what's saved
22
22
remotecli use # interactively pick the active one
23
23
```
24
24
25
-
## Non-Interactive Usage
25
+
## Driving the CLI Autonomously
26
26
27
-
Every command that normally prompts can be driven entirely with flags — always prefer flags when acting autonomously. See `references/commands.md` for every flag per command.
27
+
When acting without a human at the keyboard, every interactive prompt is friction — the TUI blocks waiting for keystrokes and your agent has no way to answer. Use this priority order; **top is always cheaper than bottom**:
28
+
29
+
### 1. Suppress the prompt with flags (preferred)
30
+
31
+
Every interactive picker has a flag equivalent. Resolve IDs via `list` filters, then pass them to the action. This requires zero special protocol and zero per-prompt round-trips.
32
+
33
+
```bash
34
+
# ❌ Picker fires — TUI blocks; the agent has no way to answer
35
+
remotecli contracts list
36
+
37
+
# ✅ Resolve the ID via a filter, then pass it
38
+
remotecli employments list --email alice@example.com --pretty
39
+
remotecli contracts list --employment-id emp_abc123
40
+
```
41
+
42
+
Same pattern for `expenses approve --expense-id`, `time-off approve --timeoff-id`, `payslips download --id`, `contract-amendments create --employment-id`, etc. See `references/commands.md` for the full flag inventory.
43
+
44
+
### 2. Use `--json-prompts` only when a prompt is unavoidable
45
+
46
+
Schema-driven flows (`employments create`, `contract-amendments create`) prompt for required fields the API doesn't expose as flags. For those, `--json-prompts` swaps the TUI for an NDJSON stdio protocol: stdout emits `{"type":"prompt", ...}` events, stdin takes one `{"answer": ...}` line per event, in order.
47
+
48
+
**Read the protocol first.** The complete spec lives in `CLAUDE.md` → "JSON prompter mode" (about 30 lines). It enumerates every event type and answer shape. Don't speculate at the format — read it once and you'll know exactly what to send.
49
+
50
+
Drive the whole flow in **one Bash call**, pre-computing every answer:
51
+
52
+
```bash
53
+
# After reading the schema (or doing a dry-run to learn the prompt order):
Splitting the flow across multiple Bash tool calls multiplies permission prompts and breaks the pipe. One process, one pipeline, one permission.
62
+
63
+
**Discovering prompts: each probe should reveal many prompts, not one.** The prompter validates answers in order and emits the next prompt *before* reading its answer, so one Bash call with N valid answers reveals N+1 prompts. Pipe several plausible answers per probe call — `0` validates as a select or number, `"2026-06-01"` as a date, a sufficiently long string as `role_description` — and read every prompt the call emits before composing the next one. Two or three probe calls is usually enough to map a whole form; firing ten one-answer-at-a-time calls is the anti-pattern, because it costs permission prompts and round-trips for no information you couldn't have learned in a single pass. Stop probing the moment field names appear that match data you already have (`job_title`, `work_hours_per_week`, `annual_gross_salary` are all in `contracts list` output) and switch to a real run with the real values.
64
+
65
+
### 3. Never write a Python wrapper
66
+
67
+
If `printf | remotecli` can't express the flow, the answer is to read the schema and pre-compute the answers — **not** to wrap the CLI in `subprocess.Popen`. A wrapper script costs:
68
+
69
+
- File-write permission to create the script
70
+
- Python execution permission to run it
71
+
- A near-guaranteed stdin-buffering bug (forgetting `flush=True`, line-buffering on pipes)
72
+
- More permission prompts every time you iterate on the script
73
+
74
+
The CLI was designed for Unix pipes. If you're reaching for Python, you've misread the protocol — go back to step 2 and re-read the `JSON prompter mode` section.
75
+
76
+
### Red flags — stop and reconsider
77
+
78
+
| You're about to... | Instead, do this |
79
+
|---|---|
80
+
| Open an interactive picker via `--json-prompts` and try to answer it | Run the matching `list` command with a filter flag, pass the resulting ID via `--<resource>-id`|
81
+
|`cat answers.txt \| remotecli --json-prompts ...` after writing the file in a separate step | Inline the answers with `printf` in a single Bash call — no temp file, no extra permission prompt |
82
+
|`python wrapper.py` that calls `subprocess.Popen(["remotecli", ...])`| Stop. Read `CLAUDE.md` → "JSON prompter mode". Use `printf \| remotecli` instead |
83
+
| Run multiple Bash tool calls to drive one CLI invocation | One Bash call, one pipeline — the CLI process should not span tool invocations |
28
84
29
85
## Quick Command Reference
30
86
@@ -38,6 +94,10 @@ Every command that normally prompts can be driven entirely with flags — always
38
94
|`employments list`| List employments |`--status`, `--email`, `--all`|
39
95
|`employments create`| Onboard a new employee |`--country`|
40
96
|`employments show <id>`| Get a single employment | — |
97
+
|`contracts list`| List contracts for an employment for historical contracts set the only-active to false |`--employment-id`, `--only-active=false`|
98
+
|`contract-amendments list`| List submitted contract amendments |`--employment-id`, `--status`, `--all`|
99
+
|`contract-amendments show <id>`| Show a single amendment | — |
100
+
|`contract-amendments create`| Submit a contract amendment |`--employment-id`, `--contract-id`, `--country`|
41
101
|`expenses list`| List expenses |`--all`, `--pretty`|
**Amend an employee's contract (salary, title, hours, etc.):**
154
+
155
+
A contract amendment is a *delta* over the current contract — never submit one without first reading the existing terms, or you'll propose changes that conflict with current state or are no-ops. When you only have a name or email, resolve the employment via `employments list` filters (not the interactive picker — filters are faster and unambiguous for autonomous use).
156
+
157
+
```bash
158
+
# 1. Resolve the employment by email/status filter (skip the picker)
159
+
remotecli employments list --email alice@example.com --pretty
160
+
161
+
# 2. Read the current active contract for context (current salary, title, work hours, etc.)
162
+
remotecli contracts list --employment-id emp_abc123 --pretty
163
+
164
+
# 3. Submit the amendment — schema-driven, country-specific, ends with a confirm step
**Most amendment fields are unchanged — copy them verbatim from the active contract.** Read the JSON form of `contracts list --employment-id X` (the default; don't pass `--pretty`) and take the first element of `data.employment_contracts`. For a salary raise, only `annual_gross_salary` (and `reason_for_change` / `effective_date`) actually change; every other answer — `job_title`, `role_description`, `work_hours_per_week`, `contract_duration_type`, `work_schedule`, `compensation_currency_code` — must equal the active contract's value, or the API records each one as an additional proposed change. Units already line up: `annual_gross_salary: 7200000` in `contracts list` means £72,000 in pence (minor units), and the form expects the same integer — don't divide by 100, don't convert to a decimal string, and don't reinvent `role_description` from scratch.
169
+
170
+
`contract-amendments create` pulls the country and `active_contract_id` off the employment automatically; override either with `--country` / `--contract-id` if needed. After submission, track the amendment with `contract-amendments list --employment-id emp_abc123` or `contract-amendments show <amendment_id>`.
Copy file name to clipboardExpand all lines: plugins/remote-cli/skills/remote-cli/references/commands.md
+70Lines changed: 70 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -124,6 +124,76 @@ Get a single employment by ID.
124
124
125
125
---
126
126
127
+
## `contracts`
128
+
129
+
### `contracts list`
130
+
131
+
List contracts (compensation snapshots) for a single employment. Use this to inspect the current and historical contract terms before submitting a contract amendment.
132
+
133
+
```bash
134
+
./remote contracts list [flags]
135
+
```
136
+
137
+
| Flag | Type | Description |
138
+
|------|------|-------------|
139
+
|`--company-token`| string | Override active company token |
140
+
|`--employment-id`| string | Employment to list contracts for (picker if omitted) |
141
+
|`--only-active`| bool | Return only the active or last active contract (default `true`; pass `--only-active=false` to list all) |
142
+
|`--columns`| string | Comma-separated column names for table output |
./remote contract-amendments show amend_abc123 [--company-token <token>]
176
+
```
177
+
178
+
### `contract-amendments create`
179
+
180
+
Submit a contract amendment for an employment. **Always run `contracts list --employment-id <id>` first** to read the current terms — the amendment is a delta over the active contract, and the schema-driven form references current-state fields (salary, title, work hours, etc.).
181
+
182
+
```bash
183
+
./remote contract-amendments create [flags]
184
+
```
185
+
186
+
| Flag | Type | Description |
187
+
|------|------|-------------|
188
+
|`--company-token`| string | Override active company token |
189
+
|`--employment-id`| string | Employment to amend (picker if omitted; prefer resolving via `employments list --email` for autonomous use) |
190
+
|`--contract-id`| string | Override the employment's `active_contract_id` (rarely needed) |
191
+
|`--country`| string | Override the employment's country (3-letter ISO; rarely needed — pulled from the employment automatically) |
192
+
193
+
The flow fetches the country-specific amendment JSON Schema, prompts for each field (with the current contract's values as defaults where the schema supports it), then shows a recap and a confirm prompt before submission. On confirm, the CLI POSTs to `/v1/contract-amendments` and returns the new `amendment_id` and `status`.
0 commit comments