Skip to content

Commit 4fe2443

Browse files
author
Remote release bot
committed
release v0.0.4
1 parent 4574da2 commit 4fe2443

5 files changed

Lines changed: 155 additions & 6 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"name": "remote-cli",
99
"source": "./plugins/remote-cli",
1010
"description": "Tools and skills for interacting with the Remote.com partner API from the command line.",
11-
"version": "v0.0.3"
11+
"version": "v0.0.4"
1212
}
1313
]
1414
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,6 @@ After installing, the `remote-cli` skill is available in Claude Code and knows h
5656

5757
## Version
5858

59-
Current release: **v0.0.3**
59+
Current release: **v0.0.4**
6060

6161
See the [Releases page](https://github.com/remoteoss/remote-cli/releases) for history.

plugins/remote-cli/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "remote-cli",
3-
"version": "v0.0.3",
3+
"version": "v0.0.4",
44
"description": "Skill that drives the `remotecli` binary against the Remote.com partner API.",
55
"author": {
66
"name": "Remote"

plugins/remote-cli/skills/remote-cli/SKILL.md

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
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.
44
---
55

66
# Using the Remote CLI
@@ -22,9 +22,65 @@ remotecli companies list # see what's saved
2222
remotecli use # interactively pick the active one
2323
```
2424

25-
## Non-Interactive Usage
25+
## Driving the CLI Autonomously
2626

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):
54+
printf '%s\n' \
55+
'{"answer":"Alice Cooper"}' \
56+
'{"answer":"alice@example.com"}' \
57+
'{"answer":"2026-06-01"}' \
58+
| remotecli --json-prompts employments create --country GBR
59+
```
60+
61+
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 |
2884

2985
## Quick Command Reference
3086

@@ -38,6 +94,10 @@ Every command that normally prompts can be driven entirely with flags — always
3894
| `employments list` | List employments | `--status`, `--email`, `--all` |
3995
| `employments create` | Onboard a new employee | `--country` |
4096
| `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` |
41101
| `expenses list` | List expenses | `--all`, `--pretty` |
42102
| `expenses create` | Submit an expense | `--employment-id`, `--amount`, `--currency`, `--expense-date`, `--title`, `--tax-amount` |
43103
| `expenses approve` | Approve a pending expense | `--expense-id` |
@@ -90,6 +150,25 @@ remotecli payslips download --id <id> --out-file ./payslip.pdf
90150
remotecli time-off balance --employment-id emp_abc123 --pretty
91151
```
92152

153+
**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
165+
remotecli contract-amendments create --employment-id emp_abc123
166+
```
167+
168+
**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>`.
171+
93172
## Output Control
94173

95174
```bash

plugins/remote-cli/skills/remote-cli/references/commands.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,76 @@ Get a single employment by ID.
124124

125125
---
126126

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 |
143+
144+
Table columns: ID, Status, Country, Job Title, Effective.
145+
146+
---
147+
148+
## `contract-amendments`
149+
150+
### `contract-amendments list`
151+
152+
List contract amendments for the active company.
153+
154+
```bash
155+
./remote contract-amendments list [flags]
156+
```
157+
158+
| Flag | Type | Description |
159+
|------|------|-------------|
160+
| `--company-token` | string | Override active company token |
161+
| `--employment-id` | string | Filter by employment ID |
162+
| `--status` | string | Filter by status: `submitted`, `in_review`, `done`, `canceled`, `deleted` |
163+
| `--columns` | string | Comma-separated column names for table output |
164+
| `--all` | bool | Fetch all pages |
165+
| `--page` | int | Page number (default: 1) |
166+
| `--page-size` | int | Results per page (default: 100) |
167+
168+
Table columns: ID, Employment, Status, Reason, Effective, Submitted.
169+
170+
### `contract-amendments show <id>`
171+
172+
Show a single contract amendment by ID.
173+
174+
```bash
175+
./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`.
194+
195+
---
196+
127197
## `expenses`
128198

129199
### `expenses list`

0 commit comments

Comments
 (0)