zas-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +286 -0
- package/dist/cli.js +1931 -0
- package/package.json +61 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this package are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-09-02
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- First release.
|
|
15
|
+
- Pairing: the agent mints its own key pair on the machine and proves it holds
|
|
16
|
+
the private half by signing a P-256 challenge; the owner approves it from the
|
|
17
|
+
web app and compares a fingerprint before they do.
|
|
18
|
+
- `zas_send_file` and `zas_send_note`: send a file or a note into a granted
|
|
19
|
+
channel, end-to-end encrypted on this machine.
|
|
20
|
+
- `zas_list_items` and `zas_get_item`: list a channel's recent items and fetch
|
|
21
|
+
one, where the grant includes reading.
|
|
22
|
+
- Per-channel grants: the agent holds one channel key per granted channel and
|
|
23
|
+
no key for any other, and the owner can add or drop a channel at any time.
|
|
24
|
+
- `--profile`, so one machine can run a Claude Code agent and a Codex agent as
|
|
25
|
+
two separate identities that cannot read each other's keys.
|
|
26
|
+
- Install snippets for Claude Code and Codex, printed by `zas-agent pair`.
|
|
27
|
+
|
|
28
|
+
[Unreleased]: https://github.com/soke1556/zas-agent/compare/v0.1.0...HEAD
|
|
29
|
+
[0.1.0]: https://github.com/soke1556/zas-agent/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sebastian Fernandez Quezada
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# zas-agent
|
|
2
|
+
|
|
3
|
+
An MCP server that lets a coding agent — Claude Code, Codex, or anything that
|
|
4
|
+
speaks MCP — send files and notes into your [Zas](https://zas.red) channels, and
|
|
5
|
+
read items back out of them.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/zas-agent)
|
|
8
|
+
[](https://github.com/soke1556/zas-agent/actions/workflows/ci.yml)
|
|
9
|
+
[](https://github.com/soke1556/zas-agent/actions/workflows/codeql.yml)
|
|
10
|
+
[](https://scorecard.dev/viewer/?uri=github.com/soke1556/zas-agent)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
|
|
13
|
+
## What it does
|
|
14
|
+
|
|
15
|
+
Your coding agent gets seven tools. It can send a file or a note into a channel
|
|
16
|
+
you picked, list what is in that channel, and pull one item back onto disk.
|
|
17
|
+
Everything it sends is encrypted on your machine before it leaves, lands in your
|
|
18
|
+
account, and is marked in the channel as sent by that agent. The agent has an
|
|
19
|
+
identity of its own and never holds your account key: pairing mints a key pair
|
|
20
|
+
here, you approve it from the web app, and from then on it signs a challenge to
|
|
21
|
+
get a short-lived session.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
Pair the machine first, then hand the command to your harness.
|
|
26
|
+
|
|
27
|
+
**Pair**
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
npx -y zas-agent pair --profile claude-code
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Claude Code**
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
claude mcp add zas -- npx -y zas-agent --profile claude-code
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Codex**
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
codex mcp add zas -- npx -y zas-agent --profile codex
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Codex by hand, if you would rather edit `~/.codex/config.toml`:
|
|
46
|
+
|
|
47
|
+
```toml
|
|
48
|
+
[mcp_servers.zas]
|
|
49
|
+
command = "npx"
|
|
50
|
+
args = ["-y", "zas-agent", "--profile", "codex"]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### What pairing prints
|
|
54
|
+
|
|
55
|
+
`zas-agent pair` mints the key pair, registers the public halves, and waits. The
|
|
56
|
+
terminal shows four things:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
Abrí esta página con tu cuenta de Zas:
|
|
60
|
+
https://zas.red/agents/pair?p=...
|
|
61
|
+
Código: ABCD-EFGH
|
|
62
|
+
Huella: 1a2b 3c4d 5e6f 7a8b
|
|
63
|
+
Esperando la aprobación… (vence en 10 minutos)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Open the link signed in to your Zas account. Check that the fingerprint on the
|
|
67
|
+
page is the one in your terminal, name the agent, and tick the channels it may
|
|
68
|
+
use — sending is the default, reading is a separate switch. The code is eight
|
|
69
|
+
characters in two groups, and it is what you compare before you approve. The
|
|
70
|
+
pairing is good for ten minutes; past that, run the command again.
|
|
71
|
+
|
|
72
|
+
You can also start the flow from the coding agent with the `zas_pair` tool: the
|
|
73
|
+
first call hands back the URL and the code, and a later call says whether the
|
|
74
|
+
approval landed.
|
|
75
|
+
|
|
76
|
+
## Why you can trust it
|
|
77
|
+
|
|
78
|
+
Every line here is a fact. The ones about this package you can check in this
|
|
79
|
+
repository. Where a property is enforced by the Zas server, which is not open
|
|
80
|
+
source, the sentence says so.
|
|
81
|
+
|
|
82
|
+
- **The agent has an identity of its own.** `zas-agent pair` generates two key
|
|
83
|
+
pairs on your machine — X25519 to receive channel keys, P-256 to sign
|
|
84
|
+
sign-ins — and the private halves never leave it. The agent never holds your
|
|
85
|
+
account key, and the key-derivation service refuses account-key derivation to
|
|
86
|
+
an agent *(server-side)*.
|
|
87
|
+
- **You approve it, and you choose the channels.** Pairing never
|
|
88
|
+
auto-approves. The approval page shows the harness, the host, the key
|
|
89
|
+
fingerprint and the code, and you compare the code with your terminal before
|
|
90
|
+
anything is granted.
|
|
91
|
+
- **It holds one key per granted channel, and no key for any other.** Each
|
|
92
|
+
grant carries that channel's key sealed to the agent's X25519 public key. A
|
|
93
|
+
channel you did not grant has no key here to decrypt with, and the server
|
|
94
|
+
checks the live grant on every request *(server-side)*.
|
|
95
|
+
- **No password and no API key.** Signing in is a signed challenge traded for a
|
|
96
|
+
one-hour token. There is no password, no API key and no refresh token on
|
|
97
|
+
disk: the agent re-signs from its P-256 key when the token ages out.
|
|
98
|
+
- **Everything it sends is visible as its work.** Every item carries the `>_`
|
|
99
|
+
agent mark and the agent's name, in the channel, on every device you read Zas
|
|
100
|
+
from.
|
|
101
|
+
- **You can revoke it at any time.** Settings → Agentes → the agent → Revocar.
|
|
102
|
+
The session stops, its refresh tokens are revoked *(server-side)*, and the
|
|
103
|
+
next tool call answers "the owner revoked this agent". What it already sent
|
|
104
|
+
stays where it is. You can also drop a single channel and keep the rest.
|
|
105
|
+
- **Content is end-to-end encrypted, the same way the app does it.** The
|
|
106
|
+
chunking, the manifest and the envelope formats under `src/shared/` are the
|
|
107
|
+
same modules the Zas web app ships. The server stores ciphertext and never
|
|
108
|
+
sees a channel key, a channel name or item plaintext *(server-side)*.
|
|
109
|
+
- **The source is here, and the releases are built from it.** Every npm release
|
|
110
|
+
is published by the `release.yml` workflow in this repository, with npm
|
|
111
|
+
provenance, so the tarball on npm can be traced back to a commit and a
|
|
112
|
+
workflow run.
|
|
113
|
+
|
|
114
|
+
## What it cannot do
|
|
115
|
+
|
|
116
|
+
The package refuses some of these on its own, before a request is made. The
|
|
117
|
+
ones marked *(server-side)* are enforced by the Zas server.
|
|
118
|
+
|
|
119
|
+
- **No channel you did not grant.** Not by name, not by id.
|
|
120
|
+
- **No shared channel you merely joined, and no workspace channel.** Grants
|
|
121
|
+
exist only on channels your account owns and that no organization manages
|
|
122
|
+
*(server-side)*.
|
|
123
|
+
- **No reading unless the grant says so.** `read` is a separate switch from
|
|
124
|
+
`send`; without it, `zas_list_items` and `zas_get_item` are refused.
|
|
125
|
+
- **No sending into a view-only channel, and none into a channel in Directo
|
|
126
|
+
mode.** Both are refused before a byte is uploaded.
|
|
127
|
+
- **Nothing outside its allowlist.** The API refuses an agent on every route
|
|
128
|
+
that is not on a short, explicit list, and Firestore rules refuse it your
|
|
129
|
+
account document, your devices, and any channel without an active read grant
|
|
130
|
+
*(server-side)*.
|
|
131
|
+
- **Rate limited by the server**, on its own buckets, with the key-derivation
|
|
132
|
+
budget charged to your account so ten agents are not ten times your own
|
|
133
|
+
allowance *(server-side)*.
|
|
134
|
+
- **Ten agents per account** *(server-side)*.
|
|
135
|
+
- **Files up to 5 GiB**, and in practice less: the agent reads a file into
|
|
136
|
+
memory to hash it, so the machine's memory is the real ceiling.
|
|
137
|
+
|
|
138
|
+
### The error vocabulary
|
|
139
|
+
|
|
140
|
+
The agent answers in a closed set of codes. Anything a server route says that
|
|
141
|
+
is not in this set collapses to `upload_failed` or `network`, so no raw server
|
|
142
|
+
string ever reaches a terminal.
|
|
143
|
+
|
|
144
|
+
| Code | What it means |
|
|
145
|
+
| --- | --- |
|
|
146
|
+
| `not_paired` | This machine is not paired yet. |
|
|
147
|
+
| `identity_corrupt` | The identity file on disk is damaged. |
|
|
148
|
+
| `agent_revoked` | The owner revoked this agent. |
|
|
149
|
+
| `agent_forbidden` | Only the account owner can do that. |
|
|
150
|
+
| `grant_missing` | This agent has no access to that channel. |
|
|
151
|
+
| `send_forbidden` | This agent cannot send to that channel. |
|
|
152
|
+
| `read_forbidden` | This agent cannot read that channel. |
|
|
153
|
+
| `direct_mode` | That channel is in Directo mode. |
|
|
154
|
+
| `not_direct_mode` | That channel is not in Directo mode. |
|
|
155
|
+
| `key_stale` | The channel key changed; the owner refreshes it by opening Zas. |
|
|
156
|
+
| `quota_exceeded` | The account reached its storage limit. |
|
|
157
|
+
| `rate_limited` | Too many sends in a row. |
|
|
158
|
+
| `file_too_big` | The file is over the plan limit. |
|
|
159
|
+
| `duplicate` | That item is already in the channel. |
|
|
160
|
+
| `not_found` | That item is not in the channel. |
|
|
161
|
+
| `invalid_cap` | That file is no longer available. |
|
|
162
|
+
| `write_failed` | The download destination could not be written. |
|
|
163
|
+
| `pairing_expired` | The pairing expired; pair again. |
|
|
164
|
+
| `pairing_cancelled` | The owner cancelled the pairing. |
|
|
165
|
+
| `feature_disabled` | Agents are not enabled for this account yet. |
|
|
166
|
+
| `upload_failed` | The upload failed. |
|
|
167
|
+
| `oprf_failed` | Zas did not answer correctly while preparing the file. |
|
|
168
|
+
| `network` | Zas cannot be reached. |
|
|
169
|
+
| `sign_in_failed` | Zas did not accept this agent session. |
|
|
170
|
+
| `bad_signature` | Zas rejected this agent's signature; pair it again. |
|
|
171
|
+
| `missing_token` | The session token is missing; pair the agent again. |
|
|
172
|
+
| `internal` | Something failed inside the agent. |
|
|
173
|
+
|
|
174
|
+
Every code comes back as one sentence in Spanish and one in English, never as a
|
|
175
|
+
stack trace.
|
|
176
|
+
|
|
177
|
+
## Tools
|
|
178
|
+
|
|
179
|
+
| Tool | What it does |
|
|
180
|
+
| --- | --- |
|
|
181
|
+
| `zas_status` | Says whether this machine is paired with a Zas account, and lists the owner's channels this agent may send to or read from. |
|
|
182
|
+
| `zas_pair` | Pairs this machine with a Zas account. The first call returns a URL and a code for the owner to approve; a later call says whether they did. |
|
|
183
|
+
| `zas_send_file` | Sends a file from this machine into one of the owner's channels. Returns the item id, or a job id when the upload takes longer than a minute. |
|
|
184
|
+
| `zas_send_note` | Sends a note — plain text, or a code snippet with its language — into one of the owner's channels. |
|
|
185
|
+
| `zas_list_items` | Lists the most recent items in one of the owner's channels. Needs a grant that includes reading. |
|
|
186
|
+
| `zas_get_item` | Fetches one item. A note comes back as text; a file is written to disk. It never overwrites, so the path it answers with can differ from the one you asked for. |
|
|
187
|
+
| `zas_jobs` | Lists the sends this server started, newest first, with the phase each one reached — and where a `job_id` from a long send is redeemed. |
|
|
188
|
+
|
|
189
|
+
`channel` takes a channel name or a channel id. A name has to match exactly one
|
|
190
|
+
of the channels you granted; with exactly one grant, `zas_send_file` and
|
|
191
|
+
`zas_send_note` can leave it out.
|
|
192
|
+
|
|
193
|
+
Two things worth knowing before you point a model at your account:
|
|
194
|
+
|
|
195
|
+
- `zas_send_file` sends any file this process can read — `~/.ssh/id_rsa` and a
|
|
196
|
+
`.env` included. Confirm with the owner before sending secrets, keys or
|
|
197
|
+
credentials. Its tool description says so, so the model reads it too.
|
|
198
|
+
- `zas_get_item` writes a new file under `dest`, or under the system temp
|
|
199
|
+
directory when you leave `dest` out. It never overwrites an existing file: a
|
|
200
|
+
name that is taken gets a suffix, and the path it answers with is the one it
|
|
201
|
+
actually wrote.
|
|
202
|
+
|
|
203
|
+
Everything either tool touches lands inside your own account and your own
|
|
204
|
+
machine. Revoking the agent stops both.
|
|
205
|
+
|
|
206
|
+
## Data on disk
|
|
207
|
+
|
|
208
|
+
One directory per profile, so one machine can hold a Claude Code agent and a
|
|
209
|
+
Codex agent side by side without either reading the other's keys:
|
|
210
|
+
|
|
211
|
+
| OS | Path |
|
|
212
|
+
| --- | --- |
|
|
213
|
+
| macOS, Linux | `~/.zas/agent/<profile>/` |
|
|
214
|
+
| Windows | `%USERPROFILE%\.zas\agent\<profile>\` |
|
|
215
|
+
|
|
216
|
+
Four files, all written through a temporary file and renamed into place, so a
|
|
217
|
+
crash mid-write cannot leave half a file behind:
|
|
218
|
+
|
|
219
|
+
- `identity.json` — the agent uid, the owner uid, the name, and the two key
|
|
220
|
+
pairs. Back it up like a private key, or delete it and pair again.
|
|
221
|
+
- `pending.json` — a pairing that has not been approved yet. Removed on
|
|
222
|
+
approval, and on a pairing that expired or was cancelled.
|
|
223
|
+
- `grants.json` — a one-minute cache of `GET /v1/agents/me`: which channels,
|
|
224
|
+
and the sealed key for each. The channel name stays encrypted here.
|
|
225
|
+
Disposable.
|
|
226
|
+
- `fingerprints.json` — hashes of what an identical send produced in the last
|
|
227
|
+
ten minutes, so a retried tool call answers without touching the network. It
|
|
228
|
+
stores hashes, never a title or a note's first line. Disposable.
|
|
229
|
+
|
|
230
|
+
On macOS and Linux the directory is created `0700` and every file `0600`. On
|
|
231
|
+
Windows those bits have no effect: the files carry the permissions of the user
|
|
232
|
+
profile they live in, and the package does not try to set any others.
|
|
233
|
+
|
|
234
|
+
Deleting the directory makes this machine forget the agent. It does not revoke
|
|
235
|
+
anything: the account side is closed from the web app, under
|
|
236
|
+
Settings → Agentes → Revocar.
|
|
237
|
+
|
|
238
|
+
## Configuration
|
|
239
|
+
|
|
240
|
+
| Setting | Default | What it changes |
|
|
241
|
+
| --- | --- | --- |
|
|
242
|
+
| `--profile <name>` | `claude-code` | Which identity directory this process uses. Letters, digits, `.`, `_` and `-`, up to 64, and it may not start with a dot. |
|
|
243
|
+
| `ZAS_AGENT_HOME` | `~/.zas/agent` | Where the profile directories live. |
|
|
244
|
+
| `ZAS_WEB_BASE` | `https://zas.red` | The web app the pairing URL points at. |
|
|
245
|
+
| `ZAS_API_BASE` | `https://zas.red/api` | The API. |
|
|
246
|
+
| `ZAS_TOKEN_BASE` | `https://zas.red/anon-token` | The challenge and token routes. |
|
|
247
|
+
| `ZAS_OPRF_BASE` | `https://zas.red/oprf` | The blind key-derivation service. |
|
|
248
|
+
| `ZAS_FIREBASE_PROJECT` | `zas-me` | The project whose Firestore the read path queries. |
|
|
249
|
+
| `ZAS_FIREBASE_API_KEY` | the public web key | The key used to exchange a custom token for a session. |
|
|
250
|
+
|
|
251
|
+
Only `--profile` and `ZAS_AGENT_HOME` are worth setting by hand. The rest exist
|
|
252
|
+
so the package can be pointed at a test deployment.
|
|
253
|
+
|
|
254
|
+
## Development
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
git clone https://github.com/soke1556/zas-agent
|
|
258
|
+
cd zas-agent
|
|
259
|
+
npm ci
|
|
260
|
+
npm test
|
|
261
|
+
npm run typecheck
|
|
262
|
+
npm run build
|
|
263
|
+
node dist/cli.js --version
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
This repository is the public mirror of the `agent/` package of Zas's private
|
|
267
|
+
monorepo. It is produced by `scripts/export-public.mjs`, which builds the
|
|
268
|
+
package with esbuild and uses the build's own metafile to decide what to copy:
|
|
269
|
+
`src/`, `test/`, the package files, and the nine `src/shared/*` modules the
|
|
270
|
+
agent imports. Those shared modules are the client-side crypto and format code — the
|
|
271
|
+
chunker, the manifest, the envelope, the key derivation — that the Zas web app
|
|
272
|
+
also ships, which is why the encryption the agent performs is the encryption the
|
|
273
|
+
app performs. The Zas server is not open source.
|
|
274
|
+
|
|
275
|
+
Pull requests are welcome against this repository. The maintainer applies
|
|
276
|
+
accepted changes back into the monorepo, and the next export brings them here.
|
|
277
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
278
|
+
|
|
279
|
+
## Security
|
|
280
|
+
|
|
281
|
+
Please report vulnerabilities privately. [SECURITY.md](SECURITY.md) says how,
|
|
282
|
+
and what to expect.
|
|
283
|
+
|
|
284
|
+
## License
|
|
285
|
+
|
|
286
|
+
MIT. See [LICENSE](LICENSE).
|