@kybernesis/create 0.8.1 → 0.9.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/dist/cli.js
CHANGED
|
@@ -60,7 +60,50 @@ function initOptions(rest) {
|
|
|
60
60
|
yes: rest.includes('--yes') || rest.includes('-y'),
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
+
/** What each command is for, in one line, as a person would ask for it. */
|
|
64
|
+
const COMMANDS = {
|
|
65
|
+
init: "Scaffold a new agent: governed, remembering, multiplayer, self-testing.",
|
|
66
|
+
doctor: "Check this machine and this project before an engagement.",
|
|
67
|
+
arcana: "Set the memory workspaces and keys this agent uses.",
|
|
68
|
+
skills: "Install the FDE skill suite (--global for every project).",
|
|
69
|
+
credential: "Write the agent credential onto a host (--local to stay here).",
|
|
70
|
+
register: "Register this agent with the control plane (--name, --url).",
|
|
71
|
+
deploy: "Deploy this agent to its host (--no-env to leave the env file alone).",
|
|
72
|
+
upgrade: "Bring @kybernesis packages and eve to the certified versions (--skip-eval).",
|
|
73
|
+
version: "Print the version of this tool.",
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Print help instead of doing anything.
|
|
77
|
+
*
|
|
78
|
+
* Given a command, describe that command; otherwise list them. Either way this
|
|
79
|
+
* function's only effect is output — which is the entire point of it existing.
|
|
80
|
+
*/
|
|
81
|
+
function usage(command) {
|
|
82
|
+
if (command && COMMANDS[command]) {
|
|
83
|
+
console.log(`\n ${bold(`kyb ${command}`)} — ${COMMANDS[command]}\n`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
console.log(`\n ${bold("kyb")} ${dim(VERSION)} — the Kybernesis agent CLI\n`);
|
|
87
|
+
for (const [name, description] of Object.entries(COMMANDS)) {
|
|
88
|
+
console.log(` ${bold(name.padEnd(12))}${description}`);
|
|
89
|
+
}
|
|
90
|
+
console.log(`\n ${dim("kyb <command> --help for one command.")}\n`);
|
|
91
|
+
}
|
|
63
92
|
const [, , command, ...rest] = process.argv;
|
|
93
|
+
/**
|
|
94
|
+
* `--help` asks what a command does. It must never be the thing that does it.
|
|
95
|
+
*
|
|
96
|
+
* Checked before dispatch rather than inside each command, because "the flag
|
|
97
|
+
* was ignored" is not a failure anyone verifies per command — and the one time
|
|
98
|
+
* it mattered, `kyb upgrade --help` ran a real upgrade against a live agent's
|
|
99
|
+
* dependencies. Nothing broke, which is the wrong kind of luck: the same
|
|
100
|
+
* mistake on a command that writes credentials or deploys would not have been
|
|
101
|
+
* survivable.
|
|
102
|
+
*/
|
|
103
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
104
|
+
usage(command);
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
64
107
|
switch (command) {
|
|
65
108
|
case "init":
|
|
66
109
|
await init(rest.find((a) => !a.startsWith("-")), initOptions(rest));
|
package/dist/upgrade.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { EVE_VERSION, bold, capture, dim, green, red, run, yellow } from "./util.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Which packages to upgrade: every `@kybernesis/*` this agent depends on.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* This was a fixed list of six, written when there were six. Four more shipped
|
|
9
|
+
* afterwards — connectors, local, manage and exe — and an agent using them was
|
|
10
|
+
* told "everything is at latest certified versions" while holding versions from
|
|
11
|
+
* months earlier. A hardcoded list does not fail loudly when it falls behind;
|
|
12
|
+
* it just quietly stops covering things, and the command that reports it is the
|
|
13
|
+
* same one that is wrong.
|
|
14
|
+
*
|
|
15
|
+
* Reading the manifest cannot fall behind. A package added tomorrow is covered
|
|
16
|
+
* by an upgrade run today.
|
|
17
|
+
*/
|
|
18
|
+
function kybernesisPackages(deps) {
|
|
19
|
+
return Object.keys(deps)
|
|
20
|
+
.filter((name) => name.startsWith("@kybernesis/"))
|
|
21
|
+
.sort();
|
|
22
|
+
}
|
|
12
23
|
function versionLt(a, b) {
|
|
13
24
|
const pa = a.split(".").map(Number);
|
|
14
25
|
const pb = b.split(".").map(Number);
|
|
@@ -52,13 +63,15 @@ export async function upgrade(skipEval) {
|
|
|
52
63
|
console.log(bold("\nkyb upgrade — checking @kybernesis/* and eve against npm\n"));
|
|
53
64
|
warnIfStale();
|
|
54
65
|
const toUpgrade = [];
|
|
55
|
-
|
|
66
|
+
const unresolved = [];
|
|
67
|
+
for (const name of kybernesisPackages(deps)) {
|
|
56
68
|
if (!deps[name])
|
|
57
69
|
continue;
|
|
58
70
|
const installed = capture("node", ["-p", `require('${name}/package.json').version`], cwd)?.trim();
|
|
59
71
|
const latest = capture("npm", ["view", name, "version"])?.trim();
|
|
60
72
|
if (!installed || !latest) {
|
|
61
73
|
console.log(` ${yellow("!")} ${name}: could not resolve versions`);
|
|
74
|
+
unresolved.push(name);
|
|
62
75
|
continue;
|
|
63
76
|
}
|
|
64
77
|
if (installed === latest)
|
|
@@ -91,6 +104,16 @@ export async function upgrade(skipEval) {
|
|
|
91
104
|
console.log(dim(` note: eve@${eveLatest} exists upstream; ${EVE_VERSION} is the newest Kybernesis-certified version.`));
|
|
92
105
|
}
|
|
93
106
|
}
|
|
107
|
+
if (toUpgrade.length === 0 && unresolved.length > 0) {
|
|
108
|
+
// Saying everything is current, having just failed to check several
|
|
109
|
+
// packages, is the worst available answer: it is the sentence someone
|
|
110
|
+
// repeats to a client. Usually the dependencies are simply not installed
|
|
111
|
+
// here, which is worth naming rather than hiding behind a green tick.
|
|
112
|
+
console.log(`\n${yellow(`Checked what could be read. ${unresolved.length} package(s) could not be ` +
|
|
113
|
+
`resolved, so this is not a clean bill of health.`)}\n` +
|
|
114
|
+
` ${dim("Usually: dependencies are not installed here. Run npm install, then kyb upgrade.")}\n`);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
94
117
|
if (toUpgrade.length === 0) {
|
|
95
118
|
console.log(`\n${green("Everything is at latest certified versions.")}\n`);
|
|
96
119
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kybernesis/create",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "The Kybernesis agent scaffolder and FDE toolkit: one command to a governed, remembering, multiplayer, self-testing eve agent — plus doctor and upgrade.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -24,9 +24,33 @@ credentials; 403 `agent_not_granted` = valid user, no grant for THIS agent.
|
|
|
24
24
|
|
|
25
25
|
Register the agent under Agents (runtime: ▲ eve + deployment URL — the row
|
|
26
26
|
shows a health probe). Grant users under their profile (grants resolve at
|
|
27
|
-
MINT time). Users page also links/revokes chat identities (
|
|
27
|
+
MINT time). Users page also links/revokes chat identities (platform id ↔ user) — the
|
|
28
|
+
manual/bulk path; see "Chat identity" below for the self-service one.
|
|
28
29
|
Sign-in for humans is RFC 8628 device flow (user code, e.g. ABCD-EFGH).
|
|
29
30
|
|
|
31
|
+
## Chat identity (how a room full of people becomes people)
|
|
32
|
+
|
|
33
|
+
`POST /api/agent/identity` — the door a channel bridge knocks on. Agent
|
|
34
|
+
authenticates with its OWN credential (`KYBERNESIS_AGENT_CREDENTIAL`), passes
|
|
35
|
+
`{provider, externalId}`, gets back `{token, bundle}` minted FOR THAT PERSON.
|
|
36
|
+
Client side is `channelIdentity()` in `@kybernesis/enterprise`.
|
|
37
|
+
|
|
38
|
+
- **Unlinked → 404 `{error:"not_linked", link}`**, not an error to show: the
|
|
39
|
+
bridge delivers that link to the sender **privately** on the platform they
|
|
40
|
+
used. Delivery IS the proof of control — a link posted in a room lets anyone
|
|
41
|
+
in that room claim to be that person. Single-use, 15 min, org-scoped.
|
|
42
|
+
- The person claims it at `/link/<code>`: they sign in as themselves, confirm,
|
|
43
|
+
and `external_identity` is written. **They must already be a user in the org**
|
|
44
|
+
(invited or SSO) or the link dead-ends at the sign-in wall — this is the
|
|
45
|
+
most likely "it didn't work" report.
|
|
46
|
+
- Linked but ungranted → 403 `agent_not_granted`; the bridge tells them so.
|
|
47
|
+
Refusals are NOT cached, so granting takes effect on their next message.
|
|
48
|
+
- Tokens are 5 min here (`CHANNEL_IDENTITY_TTL_SECONDS`), not the 1h default:
|
|
49
|
+
a bridge re-mints per turn, so revocation lands in minutes and the host holds
|
|
50
|
+
nothing durable for anybody.
|
|
51
|
+
|
|
52
|
+
Order is free: link-then-grant and grant-then-link both work.
|
|
53
|
+
|
|
30
54
|
## Timing semantics (the support-ticket section)
|
|
31
55
|
|
|
32
56
|
Token TTL defaults to 1h — that IS the revocation SLA for already-minted
|
|
@@ -42,6 +66,12 @@ appetite and tell them the number.
|
|
|
42
66
|
4. Revoke the grant → old token still works until TTL; re-mint refused.
|
|
43
67
|
5. Suspend the user → mint refused immediately; restore → mint works.
|
|
44
68
|
|
|
69
|
+
For an agent on a chat surface, the same check has a channel form, verified
|
|
70
|
+
against production 2026-08-20: unlinked sender → gets a link privately (and
|
|
71
|
+
nothing in the room); claims it → next message answers as them (the bridge log
|
|
72
|
+
names their EMAIL, not their platform id); ungranted → "no access yet"; grant →
|
|
73
|
+
works on the next message.
|
|
74
|
+
|
|
45
75
|
This exact sequence was verified against production 2026-08-05. The demo
|
|
46
76
|
moment for clients is step 3→4 — access appearing and disappearing from the
|
|
47
77
|
admin screen.
|
|
@@ -222,7 +222,9 @@ table below live.
|
|
|
222
222
|
(Photon), Telegram, Discord, Teams, SMS/phone (Twilio), GitHub, Linear, and
|
|
223
223
|
a web chat — the agent can live on several at once (§4.3c has the table and
|
|
224
224
|
install commands). Slack gets the richest treatment (our multiplayer group
|
|
225
|
-
semantics); the
|
|
225
|
+
semantics); Buzz gets the strongest identity story (§4.3c — the agent is a
|
|
226
|
+
workspace MEMBER and every turn runs as the person who sent it); the rest are
|
|
227
|
+
1:1 surfaces today. Pick with the client, then ask
|
|
226
228
|
the Slack questions below only if Slack made the list.
|
|
227
229
|
|
|
228
230
|
### 2.3a Slack specifics
|
|
@@ -706,6 +708,7 @@ re-teaching the agent. What ships:
|
|
|
706
708
|
| GitHub @mentions, PR review | GitHub | `eve add channel/github` |
|
|
707
709
|
| Linear issue delegation | Linear | `eve add channel/linear-agent` |
|
|
708
710
|
| Web app / browser chat | eve HTTP + `useEveAgent` | built-in (route auth via enterprise) |
|
|
711
|
+
| **Buzz** (agent as a workspace member) | our `@kybernesis/buzz` (§4.3c) | not an eve channel — a bridge process beside the agent |
|
|
709
712
|
|
|
710
713
|
Every channel's doc page (`node_modules/eve/docs/channels/<name>.mdx`) carries
|
|
711
714
|
its **complete** setup: the file to write, the env vars, the webhook/app
|
|
@@ -756,6 +759,48 @@ other surfaces are stock channels, excellent for 1:1; and each surface has its
|
|
|
756
759
|
own provider terms and data flow — sensitive-data review (§2.5) is per
|
|
757
760
|
channel, not per agent.
|
|
758
761
|
|
|
762
|
+
#### Buzz — the agent as a workspace member
|
|
763
|
+
|
|
764
|
+
Buzz is not an eve channel and does not go in `agent/channels/`. The agent joins
|
|
765
|
+
the workspace as a **member** with its own key, and a small bridge process runs
|
|
766
|
+
beside it. That shape buys the thing no other surface has today: every message is
|
|
767
|
+
signed by its sender, so each turn runs as **that person** — their memory, their
|
|
768
|
+
connections, their grants — instead of the whole room sharing one identity.
|
|
769
|
+
|
|
770
|
+
**What you do (the client never touches a terminal):**
|
|
771
|
+
|
|
772
|
+
```bash
|
|
773
|
+
eve add @kybernesis/buzz # deps + the workspace-behaviour instructions
|
|
774
|
+
npx kybernesis-buzz init # prints the npub to invite — do NOT regenerate later
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
Give that npub to a workspace admin to invite. Then set `BUZZ_RELAY` (the
|
|
778
|
+
workspace relay, `wss://…`), `KYBERNESIS_ISSUER` and `KYBERNESIS_AGENT_CREDENTIAL`,
|
|
779
|
+
and run it as a service:
|
|
780
|
+
|
|
781
|
+
```bash
|
|
782
|
+
npx kybernesis-buzz service /tmp/agent-buzz.service # writes a systemd unit
|
|
783
|
+
sudo mv /tmp/agent-buzz.service /etc/systemd/system/ && sudo systemctl enable --now agent-buzz
|
|
784
|
+
npx kybernesis-buzz run # or, to watch it in the foreground
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
**What the client's people do:** tag the agent → get a sign-in link **by direct
|
|
788
|
+
message** → click it, sign in, confirm. Done, once, per person. Their admin's
|
|
789
|
+
only job is in the control plane: the person must be a **user in the org first**
|
|
790
|
+
(invited or SSO), and must hold a grant on this agent unless its access tier is
|
|
791
|
+
`org`/`public`. Link-then-grant and grant-then-link both work, and a grant takes
|
|
792
|
+
effect on their next message.
|
|
793
|
+
|
|
794
|
+
**Failure modes worth knowing before a client sees them:**
|
|
795
|
+
|
|
796
|
+
- A stranger with no control-plane account gets a link that dead-ends at the
|
|
797
|
+
sign-in wall. The bridge cannot know in advance whether an unknown key belongs
|
|
798
|
+
to anyone, so this is by design — but say it out loud during setup.
|
|
799
|
+
- The key file IS the agent. Losing it means being invited again as a stranger
|
|
800
|
+
with no history; back it up with the rest of the agent's secrets.
|
|
801
|
+
- A bridge that is not running looks like an agent that is offline and ignoring
|
|
802
|
+
people, not like an error. The unit above is not optional.
|
|
803
|
+
|
|
759
804
|
### 4.3d Connections — wire the client's actual systems
|
|
760
805
|
|
|
761
806
|
A connection turns an external system into tools the model can call. Rule one:
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Use when installing, configuring, or debugging any @kybernesis package — arcana (memory), enterprise (governance), multiplayer (Slack), engineer (build+ship), dispatch (agent-to-agent), connectors (Gmail/Calendar/remote MCP), local (the user's own machine), manage (Studio→agent), exe (off-Vercel hosting), evals (QA), create (kyb CLI) — or the Kybernesis registry. Includes every production-learned gotcha.
|
|
2
|
+
description: Use when installing, configuring, or debugging any @kybernesis package — arcana (memory), enterprise (governance), multiplayer (Slack), buzz (workspace member), engineer (build+ship), dispatch (agent-to-agent), connectors (Gmail/Calendar/remote MCP), local (the user's own machine), manage (Studio→agent), exe (off-Vercel hosting), evals (QA), create (kyb CLI) — or the Kybernesis registry. Includes every production-learned gotcha.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# The Kybernesis packages
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Twelve packages, npm-public under `@kybernesis`, Apache-2.0, monorepo
|
|
8
8
|
`KybernesisAI/platform`. Registry: `https://registry.kybernesis.ai`
|
|
9
9
|
(`eve registry add @kybernesis=https://registry.kybernesis.ai/r/{name}.json`,
|
|
10
10
|
then `eve add @kybernesis/<item>`). Each covers one axis:
|
|
@@ -20,7 +20,11 @@ then `eve add @kybernesis/<item>`). Each covers one axis:
|
|
|
20
20
|
extension). `kybernesisAuth()` admits only control-plane IdentitySessions
|
|
21
21
|
WITH a grant for this agent (`authorization: Bearer` + `x-kybernesis-bundle`
|
|
22
22
|
headers; 401 no-creds, 403 agent_not_granted). Lazy JWKS — compiles without
|
|
23
|
-
KYBERNESIS_ISSUER.
|
|
23
|
+
KYBERNESIS_ISSUER. Also `channelIdentity({ issuer, credential })` — resolves a
|
|
24
|
+
chat sender (provider + platform id) to a session minted FOR THAT PERSON, per
|
|
25
|
+
turn, so a bridge never holds durable credentials for anybody. THROWS when the
|
|
26
|
+
control plane is unreachable rather than refusing: a 500 read as "not allowed"
|
|
27
|
+
locks a whole room out over a deploy. See the `control-plane` skill.
|
|
24
28
|
- **multiplayer** — Slack conversation mechanics. `multiplayerSlackChannel()`
|
|
25
29
|
from `/slack` subpath: thread = shared session with per-speaker verified
|
|
26
30
|
identity, no-re-mention continuation, dual surface (verified
|
|
@@ -82,6 +86,18 @@ then `eve add @kybernesis/<item>`). Each covers one axis:
|
|
|
82
86
|
same shape as eve's `experimental_chatgpt()`), `hostPreflight()`, Photon
|
|
83
87
|
iMessage credentials, and a `/preview` tool. Subpaths: `/slack`, `/photon`,
|
|
84
88
|
`/sandbox`, `/preview`. See the `self-hosting` skill.
|
|
89
|
+
- **buzz** — the agent as a MEMBER of a Buzz workspace (not a bot bolted on).
|
|
90
|
+
`buzzBridge()` + a `kybernesis-buzz` CLI (`init` prints the key to invite ·
|
|
91
|
+
`run` · `service` writes a systemd unit · `id` converts npub↔hex). Each turn
|
|
92
|
+
runs as the sender, resolved via `channelIdentity`; an unknown sender is sent
|
|
93
|
+
a sign-in link **privately** — holding it is what proves control of the
|
|
94
|
+
account, so a link posted in a room lets anyone there claim to be that person.
|
|
95
|
+
Publishes presence (20001, 60s heartbeat), typing (20002, every 3s) and 👀
|
|
96
|
+
(kind 7). Wire gotchas: reactions and dm-open go over HTTP with NIP-98 auth,
|
|
97
|
+
NOT the socket (a socket reaction is accepted and then never appears), and
|
|
98
|
+
command acks come back as `response:{…}` — parse without stripping that prefix
|
|
99
|
+
and a working call reads as a failure.
|
|
100
|
+
|
|
85
101
|
- **evals** — QA. `kybernesisBaseline({ agentDisplayName, routing, engineer?,
|
|
86
102
|
safety? })` = smoke + 5 memory + 1 safety (quoted content is data, on by
|
|
87
103
|
default) + routing per dept + optional engineer pair (vision loop, push-to-main
|