@kybernesis/create 0.5.2 → 0.7.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 +2 -0
- package/dist/doctor.js +27 -0
- package/dist/init.d.ts +9 -0
- package/dist/init.js +14 -0
- package/package.json +1 -1
- package/skills/control-plane/SKILL.md +26 -0
- package/skills/fde-engagement/references/playbook.md +282 -7
- package/skills/kybernesis-packages/SKILL.md +54 -2
- package/skills/self-hosting/SKILL.md +56 -1
package/dist/cli.js
CHANGED
|
@@ -22,6 +22,7 @@ function initOptions(rest) {
|
|
|
22
22
|
const subs = flag(rest, 'subagents');
|
|
23
23
|
return {
|
|
24
24
|
engineer: rest.includes('--engineer'),
|
|
25
|
+
studio: rest.includes('--studio'),
|
|
25
26
|
channel: flag(rest, "channel"),
|
|
26
27
|
host: flag(rest, "host"),
|
|
27
28
|
subagents: subs === undefined ? undefined : subs.split(',').map((s) => s.trim()).filter(Boolean),
|
|
@@ -59,6 +60,7 @@ ${bold("kyb")} — Kybernesis agent scaffolder & FDE toolkit
|
|
|
59
60
|
--host=<kind> ${dim("vercel|exe (default: vercel)")}
|
|
60
61
|
--subagents=a,b ${dim("department subagents (default: none)")}
|
|
61
62
|
--engineer ${dim("add the engineer layer: workshop sandbox + vision dev loop")}
|
|
63
|
+
--studio ${dim("wire for KYBER Studio: local execution + management routes")}
|
|
62
64
|
--yes ${dim("no prompts; take flags and defaults")}
|
|
63
65
|
${bold("kyb doctor")} preflight checks (keys, issuer, envs, discovery)
|
|
64
66
|
${bold("kyb skills")} install/refresh the FDE skill suite for Claude Code
|
package/dist/doctor.js
CHANGED
|
@@ -238,6 +238,33 @@ export async function doctor() {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
|
+
// ── KYBER Studio wiring ────────────────────────────────────────────────
|
|
242
|
+
const hasLocal = existsSync(join(cwd, "agent/tools/local_shell.ts"));
|
|
243
|
+
const hasManage = existsSync(join(cwd, "agent/channels/kyb.ts"));
|
|
244
|
+
if (hasLocal) {
|
|
245
|
+
// Without a credential the tools compile, appear in the tool list, and fail
|
|
246
|
+
// at the moment the user asks for something — the worst time to learn a
|
|
247
|
+
// deployment is incomplete. This is NOT a value to go and set by hand: the
|
|
248
|
+
// switch in Studio installs it, and a missing one means nobody has turned
|
|
249
|
+
// local access on yet.
|
|
250
|
+
if (process.env.KYBERNESIS_AGENT_CREDENTIAL) {
|
|
251
|
+
add("pass", "local execution can identify this agent to the control plane");
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
add("warn", "local execution is installed but this agent has no credential yet", "turn on 'Work on this computer' in the agent's settings in KYBER Studio — it mints and installs one; do not paste a credential by hand");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (hasManage) {
|
|
258
|
+
// manage authorizes with the caller's control-plane grant, so it needs to
|
|
259
|
+
// know which agent it IS before it can check one.
|
|
260
|
+
if (process.env.KYBERNESIS_AGENT) {
|
|
261
|
+
add("pass", "management routes can resolve this agent's grants");
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
add("fail", "management routes have no KYBERNESIS_AGENT", "KYBER Studio cannot install or write routines here: the agent cannot check a grant for a name it does not know");
|
|
265
|
+
}
|
|
266
|
+
add("warn", "management routes need a writable working copy", "installing edits this repo and rebuilds; on a read-only serverless bundle the routes refuse. Set restartCommand in agent/channels/kyb.ts or an install will not take effect");
|
|
267
|
+
}
|
|
241
268
|
// ── engineer subagent (build capability scoped to a subagent) ──────────
|
|
242
269
|
const builderDir = join(cwd, "agent/subagents/builder");
|
|
243
270
|
if (existsSync(builderDir)) {
|
package/dist/init.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { type ChannelKind, type HostKind } from "./templates.js";
|
|
2
2
|
export interface InitOptions {
|
|
3
3
|
engineer?: boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Wire this agent for KYBER Studio: local execution on the user's own machine,
|
|
6
|
+
* and management routes so Studio can install capabilities and write routines.
|
|
7
|
+
*
|
|
8
|
+
* Off by default. Both let a client reach further than chat does — one onto
|
|
9
|
+
* the user's laptop, one into the agent's own repository — so they are a
|
|
10
|
+
* deliberate choice rather than something an engagement gets by accident.
|
|
11
|
+
*/
|
|
12
|
+
studio?: boolean;
|
|
4
13
|
/** Chat surface. Default "none" — add later with `kyb add channel`. */
|
|
5
14
|
channel?: ChannelKind;
|
|
6
15
|
/** Where the agent runs. Default "vercel". */
|
package/dist/init.js
CHANGED
|
@@ -17,6 +17,7 @@ const ENGINEER_ITEMS_VERCEL = ["connection/vercel"];
|
|
|
17
17
|
const DEFAULT_MODEL = "anthropic/claude-sonnet-5";
|
|
18
18
|
export async function init(rawName, options = {}) {
|
|
19
19
|
const engineer = options.engineer === true;
|
|
20
|
+
const studio = options.studio === true;
|
|
20
21
|
const nonInteractive = options.yes === true;
|
|
21
22
|
const name = slug(rawName ?? (await ask("Agent name (kebab-case)?", "acme-agent")));
|
|
22
23
|
if (!name) {
|
|
@@ -70,6 +71,18 @@ export async function init(rawName, options = {}) {
|
|
|
70
71
|
for (const item of plan.registryItems) {
|
|
71
72
|
run("npx", ["eve", "add", item, "--overwrite"], { cwd: dir, allowFail: true });
|
|
72
73
|
}
|
|
74
|
+
if (studio) {
|
|
75
|
+
// Two separate items on purpose: `local` lets the agent act on the USER'S
|
|
76
|
+
// machine (consent per effect, granted on the desktop); `manage` lets a
|
|
77
|
+
// client change THIS AGENT — its dependencies and its source. Different
|
|
78
|
+
// blast radius, so an agent can have one without the other.
|
|
79
|
+
console.log(bold("\n2b2 KYBER Studio: local execution + management routes …"));
|
|
80
|
+
for (const item of ["local", "manage"]) {
|
|
81
|
+
const ok = run("npx", ["eve", "add", item, "--overwrite"], { cwd: dir, allowFail: true });
|
|
82
|
+
if (!ok)
|
|
83
|
+
console.log(yellow(` ! ${item} did not install cleanly — re-run: npx eve add ${item}`));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
73
86
|
const engPlan = engineer ? engineerPlan(host, DEFAULT_MODEL) : null;
|
|
74
87
|
if (engPlan) {
|
|
75
88
|
console.log(bold("\n2c Engineer subagent: workshop sandbox + vision dev loop …"));
|
|
@@ -148,6 +161,7 @@ export async function init(rawName, options = {}) {
|
|
|
148
161
|
"self-testing (evals)",
|
|
149
162
|
channel === "none" ? null : `${channel} channel`,
|
|
150
163
|
host === "exe" ? "exe.dev host" : null,
|
|
164
|
+
studio ? "KYBER Studio (local execution + management routes)" : null,
|
|
151
165
|
engineer ? "engineer subagent (workshop + vision loop)" : null,
|
|
152
166
|
depts.length ? `${depts.length} dept subagent(s)` : null,
|
|
153
167
|
].filter(Boolean);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kybernesis/create",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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",
|
|
@@ -46,6 +46,32 @@ This exact sequence was verified against production 2026-08-05. The demo
|
|
|
46
46
|
moment for clients is step 3→4 — access appearing and disappearing from the
|
|
47
47
|
admin screen.
|
|
48
48
|
|
|
49
|
+
## It also brokers connectors and the user's own machine
|
|
50
|
+
|
|
51
|
+
Governance was the first job; the plane now also holds the two things an agent
|
|
52
|
+
cannot hold itself.
|
|
53
|
+
|
|
54
|
+
**Connectors** (`/api/connectors`, `link`, `disconnect`, `tools`, `execute`,
|
|
55
|
+
`custom`, `mcp`, `mcp/test`). Each ORG holds its own broker (Composio) API key,
|
|
56
|
+
encrypted at rest with `SECRET_ENCRYPTION_KEY` (AES-256-GCM,
|
|
57
|
+
`v1:<iv>:<tag>:<ct>`), set
|
|
58
|
+
through the admin — never an env var, never our key used for a client. The
|
|
59
|
+
agent asks the plane which services the CURRENT principal has connected;
|
|
60
|
+
`@kybernesis/connectors` turns the answer into tools for that turn only. The
|
|
61
|
+
broker's entity is `<registered-agent-name>:<userId>` — the registered NAME,
|
|
62
|
+
not the agent's UUID.
|
|
63
|
+
|
|
64
|
+
**Local access** (`/api/local-exec/*`). A device enrolls, the user grants it
|
|
65
|
+
once, and that grant is STANDING — no expiry. Requests and responses are relayed
|
|
66
|
+
as frames; the plane never executes anything. See `@kybernesis/local`.
|
|
67
|
+
|
|
68
|
+
**A client must refresh on the earlier of the token and the bundle.** They have
|
|
69
|
+
independent lifetimes: a token with 57 minutes left and a bundle with 12 will
|
|
70
|
+
start returning 401 while every dashboard says the session is fine. This cost a
|
|
71
|
+
full day, presented to the user as "log out and log back in", and the fix is one
|
|
72
|
+
line — `Math.min(tokenExpiry, bundleExpiry)`. On a 401, force a refresh and
|
|
73
|
+
retry ONCE before showing a human anything.
|
|
74
|
+
|
|
49
75
|
## Boundaries to state plainly
|
|
50
76
|
|
|
51
77
|
Control-plane grants govern the HTTP/desktop doors — NOT the Slack door
|
|
@@ -44,6 +44,9 @@ npm create @kybernesis acme-atlas -- --engineer
|
|
|
44
44
|
# ChatGPT/LLM subscription paying for inference. See section 11:
|
|
45
45
|
npm create @kybernesis acme-atlas -- --host=exe --engineer
|
|
46
46
|
|
|
47
|
+
# …or, when the client wants the desktop app (KYBER Studio) — see section 12:
|
|
48
|
+
npm create @kybernesis acme-atlas -- --studio
|
|
49
|
+
|
|
47
50
|
# 3. (Optional, for repeated use) put `kyb` on the PATH for the whole engagement:
|
|
48
51
|
npm install -g @kybernesis/create
|
|
49
52
|
```
|
|
@@ -1870,6 +1873,45 @@ client with an existing ChatGPT or Claude subscription pays no incremental
|
|
|
1870
1873
|
inference cost for the pilot. Say the number out loud in the discovery
|
|
1871
1874
|
conversation — it changes the shape of the deal.
|
|
1872
1875
|
|
|
1876
|
+
**Grok, on a SuperGrok or X Premium+ subscription.** Same arrangement, without
|
|
1877
|
+
the broker: xAI's Grok Build CLI does a device login and writes a credential
|
|
1878
|
+
that is a valid bearer for `https://api.x.ai/v1`. Proven in production on Sid —
|
|
1879
|
+
twelve evals, twenty-nine gates, green on the subscription.
|
|
1880
|
+
|
|
1881
|
+
```bash
|
|
1882
|
+
# on the host, as the unix user the agent runs as
|
|
1883
|
+
curl -fsSL https://x.ai/cli/install.sh | bash
|
|
1884
|
+
grok login # device flow → ~/.grok/auth.json
|
|
1885
|
+
```
|
|
1886
|
+
|
|
1887
|
+
```ts title="agent/agent.ts"
|
|
1888
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
1889
|
+
import { grokSubscription } from "@kybernesis/exe";
|
|
1890
|
+
|
|
1891
|
+
export default defineAgent({
|
|
1892
|
+
model: grokSubscription({ model: "grok-4.6", createOpenAI }),
|
|
1893
|
+
modelContextWindowTokens: 400_000,
|
|
1894
|
+
});
|
|
1895
|
+
```
|
|
1896
|
+
|
|
1897
|
+
Three things to know before you promise it to a client:
|
|
1898
|
+
|
|
1899
|
+
- The credential is **per-machine and per-user**. It lives in a home directory.
|
|
1900
|
+
A different unix user cannot see it; a new host needs its own login.
|
|
1901
|
+
- It **expires in six hours** and the CLI refreshes it in place, so the agent
|
|
1902
|
+
must re-read the file per request. `grokSubscription` does this in a `fetch`
|
|
1903
|
+
wrapper. (Do not reach for a Proxy around the model object — the AI SDK's
|
|
1904
|
+
methods depend on their own `this` and every call dies inside the SDK.)
|
|
1905
|
+
- **Unattended refresh over days is unverified.** If nobody runs `grok` on that
|
|
1906
|
+
host for a week, it is an open question, and it would present to the client as
|
|
1907
|
+
the agent breaking for no reason.
|
|
1908
|
+
|
|
1909
|
+
**The model will lie about which model it is.** Sid, running Grok, stated it was
|
|
1910
|
+
"Claude Opus 4.6, Anthropic" and attributed it to an instruction that exists
|
|
1911
|
+
nowhere in its context. Verify from the host — the configured model id and the
|
|
1912
|
+
credential in use — never by asking the agent. Expect a client to ask it in a
|
|
1913
|
+
demo, and have the real answer ready.
|
|
1914
|
+
|
|
1873
1915
|
### 11.5 Third-party APIs: broker the credential, pin the version
|
|
1874
1916
|
|
|
1875
1917
|
Do not put a client's API token on the agent host. Put it in an exe.dev
|
|
@@ -1971,6 +2013,40 @@ Also: a long-lived channel session caches the compiled agent. After changing
|
|
|
1971
2013
|
capabilities, start a **fresh conversation** before deciding the change did not
|
|
1972
2014
|
work.
|
|
1973
2015
|
|
|
2016
|
+
**A restart script must do two more things, and both were learned from a
|
|
2017
|
+
stranded user.**
|
|
2018
|
+
|
|
2019
|
+
*Serialize restarts.* `@kybernesis/manage` fires one 20s after any change, and
|
|
2020
|
+
you will also run one by hand. Two overlapping runs both finish killing before
|
|
2021
|
+
either starts, and you end up with **two supervisors and two servers writing to
|
|
2022
|
+
one durable store** — two executors racing over the same runs. That is not a
|
|
2023
|
+
slow agent, it is a corrupt one. Take a `flock` at the top of the script, and
|
|
2024
|
+
assert exactly one server process at the bottom.
|
|
2025
|
+
|
|
2026
|
+
*Wait for in-flight turns.* eve does **not** resume a step killed mid-flight.
|
|
2027
|
+
Restart into a live turn and that turn never emits another event, the session
|
|
2028
|
+
never parks, and every later message queues behind a turn that will never
|
|
2029
|
+
finish. The user watches a spinner forever, and no further restart fixes it,
|
|
2030
|
+
because the session is stranded rather than stuck. Poll
|
|
2031
|
+
`.eve/.workflow-data/runs/*.json` for a `turnWorkflow` in `running` state and
|
|
2032
|
+
wait for it to clear — with a cap, so a wedged turn cannot block the restart
|
|
2033
|
+
that would clear it.
|
|
2034
|
+
|
|
2035
|
+
*And measure it correctly.* `pgrep -f 'server/index.mjs'` run over ssh matches
|
|
2036
|
+
**the shell running the pgrep** — the pattern is in its own command line — so it
|
|
2037
|
+
reports two servers when there is one. An entire investigation went into hunting
|
|
2038
|
+
a phantom supervisor that a `ps -eo pid,ppid,args` would have dismissed in
|
|
2039
|
+
thirty seconds. Same family as `pkill -f` killing its caller. Inside a script
|
|
2040
|
+
file it is safe (the script's command line is `bash restart.sh`); typed at a
|
|
2041
|
+
shell or sent over ssh it is not. When a process count surprises you, **list the
|
|
2042
|
+
matches before believing the number.**
|
|
2043
|
+
|
|
2044
|
+
The escape from an already-stranded session is a **session reset**
|
|
2045
|
+
(`ClientSession.reset()`, or Reset in Studio's agent settings), which releases
|
|
2046
|
+
the durable owner so the next message starts a fresh conversation. Cancelling
|
|
2047
|
+
often does not help: the executor that would honour the cancel is the one that
|
|
2048
|
+
died.
|
|
2049
|
+
|
|
1974
2050
|
### 11.9 Credential checklist — collect ALL of these from the client
|
|
1975
2051
|
|
|
1976
2052
|
Nothing here can be borrowed from another agent or another account.
|
|
@@ -1990,7 +2066,192 @@ Nothing here can be borrowed from another agent or another account.
|
|
|
1990
2066
|
against the client's `-eval` workspace, and a live turn on the real surface —
|
|
1991
2067
|
sent from the client's own device, not yours.
|
|
1992
2068
|
|
|
1993
|
-
## 12.
|
|
2069
|
+
## 12. KYBER Studio — the desktop surface
|
|
2070
|
+
|
|
2071
|
+
Slack and iMessage reach an agent where the client already works. KYBER Studio
|
|
2072
|
+
is the third door: a desktop app for people who do not live in a chat tool, and
|
|
2073
|
+
the only surface where an agent can work on the user's own files.
|
|
2074
|
+
|
|
2075
|
+
Reach for it when the client says any of: *"not everyone here uses Slack"*,
|
|
2076
|
+
*"I want it on my laptop"*, *"can it look at our repo"*, or when the pilot
|
|
2077
|
+
involves someone technical who will hand the agent real work.
|
|
2078
|
+
|
|
2079
|
+
### 12.1 What it is
|
|
2080
|
+
|
|
2081
|
+
- **The same agent.** Studio does not run anything. It talks to the agent you
|
|
2082
|
+
deployed — same memory, same tools, same subagents. Nothing to deploy twice.
|
|
2083
|
+
- **Governed by the same grants.** Sign-in is control-plane device flow, so
|
|
2084
|
+
desktop access is the grant you already manage. Revoke it and the desktop goes
|
|
2085
|
+
with it.
|
|
2086
|
+
- **Optionally hands and eyes.** With `@kybernesis/local` the agent can search,
|
|
2087
|
+
read, edit, write, and run commands on the user's machine, with consent.
|
|
2088
|
+
- **Optionally self-modifying.** With `@kybernesis/manage` the client can
|
|
2089
|
+
install capabilities and write routines from the app instead of asking you.
|
|
2090
|
+
|
|
2091
|
+
### 12.2 The two packages, and why they are separate
|
|
2092
|
+
|
|
2093
|
+
| | What it lets happen | Installed on |
|
|
2094
|
+
| --- | --- | --- |
|
|
2095
|
+
| `@kybernesis/local` | The agent acts on the USER's machine | the agent |
|
|
2096
|
+
| `@kybernesis/manage` | A client changes THE AGENT — deps and source | the agent |
|
|
2097
|
+
|
|
2098
|
+
Different blast radius, so they are separate items an engagement chooses
|
|
2099
|
+
independently. A reporting agent might want `local` and never `manage`. Neither
|
|
2100
|
+
is installed by default, because both let a client reach further than chat does.
|
|
2101
|
+
|
|
2102
|
+
```bash
|
|
2103
|
+
kyb init acme-agent --host=exe --studio # both, at scaffold time
|
|
2104
|
+
npx eve add local # or either one, later
|
|
2105
|
+
npx eve add manage
|
|
2106
|
+
```
|
|
2107
|
+
|
|
2108
|
+
`kyb doctor` checks both: the relay secret for local, and `KYBERNESIS_AGENT` for
|
|
2109
|
+
manage, since it cannot check a grant for a name it does not know.
|
|
2110
|
+
|
|
2111
|
+
### 12.3 Prerequisites, in order
|
|
2112
|
+
|
|
2113
|
+
1. **The agent is registered in the control plane** and the pilot users are
|
|
2114
|
+
granted. Studio lists exactly what a user has a grant for — an agent that is
|
|
2115
|
+
registered but ungranted is invisible, which is the correct behaviour and a
|
|
2116
|
+
confusing one if you forget you did it.
|
|
2117
|
+
2. **The agent has a URL on file.** Studio reads `/api/me/agents`; an agent with
|
|
2118
|
+
no deployment URL appears as unreachable rather than silently missing.
|
|
2119
|
+
3. **For `manage`: a writable working copy.** Installing edits the repo and
|
|
2120
|
+
rebuilds, so it works on a VM and refuses on a read-only serverless bundle,
|
|
2121
|
+
with that reason. Set `restartCommand` in `agent/channels/kyb.ts` or an
|
|
2122
|
+
install completes without taking effect.
|
|
2123
|
+
4. **For `local`: nothing to configure.** Setup is one switch in Studio — the
|
|
2124
|
+
agent's settings, *Work on this computer*. Behind it, Studio mints the
|
|
2125
|
+
agent's credential from the control plane, installs it over the manage
|
|
2126
|
+
channel, and records a standing grant for that machine; the agent restarts
|
|
2127
|
+
once to load it. Never hand anyone a credential to paste into an env file.
|
|
2128
|
+
The admin UI's "mint agent credential (shown once)" button remains for
|
|
2129
|
+
recovery and is not the path: a setup step that asks someone to carry a
|
|
2130
|
+
secret between two screens gets done wrong or skipped.
|
|
2131
|
+
|
|
2132
|
+
### 12.4 What consent looks like for the user
|
|
2133
|
+
|
|
2134
|
+
Studio asks per **effect** — run a command, read a file, write a file, list a
|
|
2135
|
+
directory — not per tool, and not per turn. Approving `read-file` once covers
|
|
2136
|
+
every tool that reads a file out, which is why adding a tool later cannot dodge
|
|
2137
|
+
a decision the user already made.
|
|
2138
|
+
|
|
2139
|
+
The default is ask. A working folder can be set, but it is a starting directory
|
|
2140
|
+
rather than a fence: permission to act on the machine is granted once, and the
|
|
2141
|
+
agent may work wherever it is asked to. Whether it builds in its own sandbox or
|
|
2142
|
+
on the user's files is decided by the ask, not by a mode — the same way a
|
|
2143
|
+
colleague knows "build me a demo" from "look at my repo".
|
|
2144
|
+
|
|
2145
|
+
### 12.5 State this plainly to the client
|
|
2146
|
+
|
|
2147
|
+
- **Two things gate a laptop, and they fail differently.** *Identity* is the
|
|
2148
|
+
agent's signed credential — "the local-execution relay rejected my
|
|
2149
|
+
credentials" means that. *Consent* is a standing per-device grant — "you have
|
|
2150
|
+
not allowed this agent to work on this computer" means that. Neither alone
|
|
2151
|
+
reaches anything. The grant is permanent on purpose: "always allow" means
|
|
2152
|
+
always, from a chat window, a schedule, or a message sent from a phone, and it
|
|
2153
|
+
ends on revoke, device removal, or disabling the agent.
|
|
2154
|
+
- **Reaching a desktop is still not its own revocable capability.** "May talk to
|
|
2155
|
+
this agent" and "may run commands on my laptop" remain one decision, taken
|
|
2156
|
+
when the person allows the machine. Say so at a client who would treat it as a
|
|
2157
|
+
surprise.
|
|
2158
|
+
- **Installing the credential restarts the agent**, and a turn in flight during
|
|
2159
|
+
that restart is lost for good — eve does not resume a step killed mid-flight.
|
|
2160
|
+
It reads as a spinner that never resolves, often alongside a "credential is
|
|
2161
|
+
unset" error from the process that was replaced. Send a new message, and reset
|
|
2162
|
+
the conversation if the session itself is stranded. §11.8 is why a restart
|
|
2163
|
+
script must wait for in-flight turns.
|
|
2164
|
+
- **Reading a file sends it to the model.** Execution is local; the reasoning is
|
|
2165
|
+
not. Fine for most work, and a conversation to have before a Studio points at
|
|
2166
|
+
a regulated repository.
|
|
2167
|
+
- **Management routes let a client change the agent.** That is the point, and it
|
|
2168
|
+
means the repository is no longer only yours. Agree who reviews what Studio
|
|
2169
|
+
writes — routines land as source files, so a normal review works.
|
|
2170
|
+
|
|
2171
|
+
### 12.7 Connectors — the apps library
|
|
2172
|
+
|
|
2173
|
+
The Apps tab in Studio is a shelf of services a person connects in one click:
|
|
2174
|
+
Gmail, Calendar, Drive, Slack, Notion, Linear, GitHub, Attio, Outlook, HubSpot.
|
|
2175
|
+
Connecting one makes its tools appear in that person's next session.
|
|
2176
|
+
|
|
2177
|
+
**Setup is one field, and it belongs to the client.** The org's own Composio key
|
|
2178
|
+
goes in their control plane at **Settings → Connectors**, set by an owner, the
|
|
2179
|
+
same way SSO is. It is never a deployment env var and never ours: each control
|
|
2180
|
+
plane belongs to one company, and nobody's people connect their mailboxes under
|
|
2181
|
+
another org's account. Direct them to composio.dev → Settings → API Keys.
|
|
2182
|
+
|
|
2183
|
+
**What makes it one click** is that Composio has already registered the OAuth
|
|
2184
|
+
app for each service. Without a broker, every client has to create a developer
|
|
2185
|
+
app per provider — which is exactly the hour lost to Notion on the first
|
|
2186
|
+
deployment, version pin and all.
|
|
2187
|
+
|
|
2188
|
+
**Two things on every card, because both are load-bearing:**
|
|
2189
|
+
|
|
2190
|
+
*Connects as you* versus *for the company*. A user-scoped connection cannot fire
|
|
2191
|
+
from a schedule — a routine at 8am has no signed-in person. Anything a briefing
|
|
2192
|
+
depends on must be the company's connection.
|
|
2193
|
+
|
|
2194
|
+
*An admin must approve*. True for Slack, Notion, and Google Workspace. Say it on
|
|
2195
|
+
the card; a client who discovers it at the end of a redirect chain reads the
|
|
2196
|
+
product as broken.
|
|
2197
|
+
|
|
2198
|
+
**How tools reach the agent.** `@kybernesis/connectors` mounts a dynamic
|
|
2199
|
+
resolver in `agent/tools/connectors.ts`. It resolves per session from the
|
|
2200
|
+
principal on the turn, asks the control plane what that person has connected,
|
|
2201
|
+
and calls back through it to execute. The agent never holds the broker key — it
|
|
2202
|
+
proves which agent it is with its own credential, and the control plane decides
|
|
2203
|
+
whose account the call runs against.
|
|
2204
|
+
|
|
2205
|
+
Resolution is per session, not per turn: a tool set is part of the prompt, and
|
|
2206
|
+
rebuilding it every turn re-ingests the conversation at uncached prices. Pass
|
|
2207
|
+
`perTurn: true` where people connect things mid-conversation and expect them to
|
|
2208
|
+
work immediately.
|
|
2209
|
+
|
|
2210
|
+
**Say this to the client.** Their Composio account holds refresh tokens for
|
|
2211
|
+
their Google Workspace and Slack — a fourth party alongside the model provider,
|
|
2212
|
+
the host, and us. Most will not blink; a regulated one will, and the answer for
|
|
2213
|
+
them is `eve-connect`, native eve connections with no broker. That is why every
|
|
2214
|
+
card carries a `provider`.
|
|
2215
|
+
|
|
2216
|
+
**And watch the bill.** Composio prices per action. An agent in a loop is a very
|
|
2217
|
+
different cost profile from a person clicking, and that belongs in the pricing
|
|
2218
|
+
conversation before the first invoice, not after.
|
|
2219
|
+
|
|
2220
|
+
### 12.8 MCP servers — the client's own tools, local and remote
|
|
2221
|
+
|
|
2222
|
+
The MCP tab is the escape hatch from the shelf: anything with an MCP server
|
|
2223
|
+
becomes agent tools, whether it runs on the person's laptop or on a URL.
|
|
2224
|
+
|
|
2225
|
+
**Local** — a command Studio runs on that machine (`npx -y @acme/mcp`, with env
|
|
2226
|
+
vars if the server needs them). Studio keeps it alive, and the deployed agent
|
|
2227
|
+
reaches it through the same relay as local execution. This is how a client's
|
|
2228
|
+
internal tooling — the CLI nobody will ever expose to the internet — becomes
|
|
2229
|
+
something the agent can use, without opening a port.
|
|
2230
|
+
|
|
2231
|
+
**Remote** — a URL and optional headers. Studio runs the handshake before
|
|
2232
|
+
saving, so a bad URL fails at the moment someone types it rather than in the
|
|
2233
|
+
middle of a demo.
|
|
2234
|
+
|
|
2235
|
+
Consent is **per server**, and approving one does not approve the next. The
|
|
2236
|
+
discovery call (listing what a server offers) is exempt — otherwise a person is
|
|
2237
|
+
asked to approve something before they can see what it is.
|
|
2238
|
+
|
|
2239
|
+
The things that cost real sessions here:
|
|
2240
|
+
|
|
2241
|
+
- **The command in a vendor's README is often the installer**, not the server.
|
|
2242
|
+
Plaud's documented line runs an `install` subcommand and exits; the stdio
|
|
2243
|
+
server is the bare command. If a server "connects" and never answers, check
|
|
2244
|
+
that you are running the server.
|
|
2245
|
+
- **A server declares its arguments and you must honour them.** Studio passes
|
|
2246
|
+
the published `inputSchema` through to the model (`@kybernesis/local` ≥0.5.0).
|
|
2247
|
+
Before that it did not, and watching the result is the best argument for the
|
|
2248
|
+
fix: nine consecutive calls guessing the name of an argument the server had
|
|
2249
|
+
documented, steered only by error strings.
|
|
2250
|
+
- **Discovery must have a deadline.** These resolvers run before a turn and
|
|
2251
|
+
reach across a network to a laptop that might be shut. Budgeted at 6s with a
|
|
2252
|
+
five-minute cache; without that, one closed lid makes every turn hang.
|
|
2253
|
+
|
|
2254
|
+
## 13. Known gaps — state these plainly, do not sell around them
|
|
1994
2255
|
|
|
1995
2256
|
Being straight about these is a feature. Clients have met vendors who were not.
|
|
1996
2257
|
|
|
@@ -2007,9 +2268,12 @@ Being straight about these is a feature. Clients have met vendors who were not.
|
|
|
2007
2268
|
requester or a `manage`-grant holder may approve — are the planned governance half in
|
|
2008
2269
|
`@kybernesis/enterprise`.
|
|
2009
2270
|
|
|
2010
|
-
3. **
|
|
2011
|
-
|
|
2012
|
-
|
|
2271
|
+
3. **The desktop door is built** — KYBER Studio, signed and notarized, with device-flow
|
|
2272
|
+
sign-in and in-app updates. What is NOT built is a second consent system talking to
|
|
2273
|
+
the first: the control plane holds the standing per-device grant, Studio holds
|
|
2274
|
+
per-effect permissions in a local file, and revoking in one does not revoke the
|
|
2275
|
+
other. An off-boarding story that says "we revoke access centrally" must be qualified
|
|
2276
|
+
at any client that asks the follow-up question.
|
|
2013
2277
|
|
|
2014
2278
|
4. **Off-boarding SLA equals the token TTL** (1h default) for already-minted sessions.
|
|
2015
2279
|
Suspension is immediate; revocation is not. Tune `IDENTITY_TOKEN_TTL_SECONDS` to the
|
|
@@ -2020,9 +2284,20 @@ Being straight about these is a feature. Clients have met vendors who were not.
|
|
|
2020
2284
|
a time per session — simultaneous speakers resolve in arrival order, with mid-turn
|
|
2021
2285
|
messages folded into the next turn best-effort.
|
|
2022
2286
|
|
|
2023
|
-
6. **Per-user OAuth
|
|
2024
|
-
|
|
2025
|
-
|
|
2287
|
+
6. **Per-user OAuth and local-file work are BUILT** — §12.6 and §12.7, both proven end
|
|
2288
|
+
to end. The remaining edge is the one that bites unattended: anything without a
|
|
2289
|
+
signed-in person (a schedule, a subagent) has no user principal, so a user-scoped
|
|
2290
|
+
connection is not available to it. A morning briefing built on someone's personal
|
|
2291
|
+
Gmail connection does not fail loudly — it quietly has no tools. Company-scoped
|
|
2292
|
+
connections are the answer, and that path has not yet been exercised in production.
|
|
2293
|
+
|
|
2294
|
+
Two more, worth saying because a client will meet them:
|
|
2295
|
+
|
|
2296
|
+
- **Tool volume is unmanaged.** Gmail and Calendar alone are 51 tool definitions in
|
|
2297
|
+
every prompt. Real tokens per turn, and measurably worse tool selection as a client
|
|
2298
|
+
connects more. Curation is designed, not shipped — connect what the pilot needs.
|
|
2299
|
+
- **Local MCP servers are per-machine.** A person's second laptop silently has a
|
|
2300
|
+
different set, and nothing in the UI says which machine a server is on.
|
|
2026
2301
|
|
|
2027
2302
|
7. **DM memory is per-workspace, not per-employee, unless you build it.** Splitting DMs
|
|
2028
2303
|
into one Arcana workspace per person needs a Slack-user-id → workspace-slug map in the
|
|
@@ -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), 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), 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
|
+
Eleven 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:
|
|
@@ -60,6 +60,28 @@ then `eve add @kybernesis/<item>`). Each covers one axis:
|
|
|
60
60
|
0.2.1 lesson: eve resolves remote URLs at BOOT — url() must degrade
|
|
61
61
|
(env → discovery-if-credentialed → fallbackUrl), never throw on a missing
|
|
62
62
|
credential, or the whole agent (and its evals) fails to boot.
|
|
63
|
+
- **connectors** — the user's SaaS accounts, brokered. `connectorTools()` is a
|
|
64
|
+
dynamic resolver: at turn start it asks the control plane which services THIS
|
|
65
|
+
principal has connected and returns those tools. Composio is the broker; the
|
|
66
|
+
API key is per-org, held in the control plane (never an env var, never a
|
|
67
|
+
client's key in our account). Tools are named `<toolkit>_<action>`. Also
|
|
68
|
+
exports `toolInputSchema` (broker JSON Schema → zod) and a minimal MCP client
|
|
69
|
+
for `mcp-direct` servers that speaks BOTH JSON and text/event-stream.
|
|
70
|
+
- **local** — the user's own machine, through KYBER Studio. `localShellTool`,
|
|
71
|
+
`localRead/List/Write/Edit/SearchTool`, plus `localMcpTools()` for MCP servers
|
|
72
|
+
running on that machine, relayed. Every effect is consented in Studio; the
|
|
73
|
+
agent never holds a shell. `LOCAL_INSTRUCTIONS` explains the arrangement to
|
|
74
|
+
the model — mount it or the agent will offer to do things it cannot do.
|
|
75
|
+
- **manage** — the other direction: `manageChannel()` lets Studio install
|
|
76
|
+
capabilities and write schedules onto a running agent, and `routineTools()`
|
|
77
|
+
turns "every morning at 8, brief me" into a real schedule file. This is how a
|
|
78
|
+
routine gets created from chat without anyone touching the repo.
|
|
79
|
+
- **exe** — running off Vercel. `exeModel()` for exe.dev's LLM integration,
|
|
80
|
+
`grokSubscription()` / `readGrokCredential()` for a SuperGrok or X Premium+
|
|
81
|
+
login (`grok login` → `~/.grok/auth.json`, a valid bearer for api.x.ai —
|
|
82
|
+
same shape as eve's `experimental_chatgpt()`), `hostPreflight()`, Photon
|
|
83
|
+
iMessage credentials, and a `/preview` tool. Subpaths: `/slack`, `/photon`,
|
|
84
|
+
`/sandbox`, `/preview`. See the `self-hosting` skill.
|
|
63
85
|
- **evals** — QA. `kybernesisBaseline({ agentDisplayName, routing,
|
|
64
86
|
engineer? })` = smoke + 5 memory + routing per dept + optional vision-loop
|
|
65
87
|
eval. Judge model ≠ model under test. Hermetic runs force all workspaces to
|
|
@@ -91,6 +113,36 @@ then `eve add @kybernesis/<item>`). Each covers one axis:
|
|
|
91
113
|
company-general wording (dept-flavored prompts delegate and hide tool
|
|
92
114
|
calls), no security vocabulary ("canary" triggers refusals), long routing
|
|
93
115
|
timeouts. Do not "clean up" the odd-looking patterns.
|
|
116
|
+
- **A per-turn dynamic resolver needs a deadline.** `connectorTools()` and
|
|
117
|
+
`localMcpTools()` run before every turn and reach across a network. Without a
|
|
118
|
+
budget (6s) and a cache (60s connectors, 5min local discovery) one unreachable
|
|
119
|
+
laptop makes every turn hang — the agent looks broken and nothing in the log
|
|
120
|
+
says why.
|
|
121
|
+
- **Composio: one request per toolkit.** Repeating `toolkit_slug` in a single
|
|
122
|
+
`/api/v3/tools` call returns an EMPTY list, so connecting a second service
|
|
123
|
+
silently emptied the first. The logo is at `meta.logo`, not `logo`. A 200 can
|
|
124
|
+
still carry `successful: false` — check the body, not the status.
|
|
125
|
+
- **The broker's entity is the agent's REGISTERED name**, not its UUID.
|
|
126
|
+
`<agent>:<userId>`. Studio knows agents by id; normalize before you ask the
|
|
127
|
+
broker, or a connected account looks unconnected.
|
|
128
|
+
- **MCP requires the handshake.** `initialize` AND `notifications/initialized`
|
|
129
|
+
before `tools/list`, or the server never answers. Spawn through a LOGIN shell
|
|
130
|
+
(a bare spawn misses the user's PATH and node) and always bind
|
|
131
|
+
`child.on("error")` — without it a failed spawn is an unhandled rejection
|
|
132
|
+
that takes the process, not a error message.
|
|
133
|
+
- **Translate the MCP/broker inputSchema — never pass an open object.** A tool
|
|
134
|
+
with no declared arguments makes the model guess: nine calls to find a
|
|
135
|
+
`file_id` the server had documented all along. `mcpInputSchema` (local) and
|
|
136
|
+
`toolInputSchema` (connectors) do this; keep them permissive where the server
|
|
137
|
+
says nothing.
|
|
138
|
+
- **Never wrap a model object in a Proxy.** The AI SDK's model methods depend on
|
|
139
|
+
their own `this`; intercepting them detaches it and every call dies inside the
|
|
140
|
+
SDK on a missing internal. To swap a credential, wrap `fetch` instead — and
|
|
141
|
+
re-read the credential per request: a Grok login expires in six hours and the
|
|
142
|
+
CLI refreshes it in place.
|
|
143
|
+
- **Credentials are never a user's problem.** No client ever puts a key in a
|
|
144
|
+
`.env` — broker keys live per-org in the control plane, encrypted at rest, set
|
|
145
|
+
through an admin screen. A design that ends in "paste this token" is wrong.
|
|
94
146
|
- **npm**: only the `kybernesis` account creates new packages in the scope;
|
|
95
147
|
publishes need the human's browser auth; new versions take 1–3 min to
|
|
96
148
|
propagate to anonymous reads.
|
|
@@ -25,7 +25,7 @@ kyb init <name> --host=exe --channel=<imessage|slack|telegram|none> --engineer
|
|
|
25
25
|
|
|
26
26
|
| Capability | On Vercel | Self-hosted replacement |
|
|
27
27
|
| --- | --- | --- |
|
|
28
|
-
| Model access | AI Gateway | exe.dev LLM integration (`exeModel`) — managed, BYO key, or a **ChatGPT subscription** |
|
|
28
|
+
| Model access | AI Gateway | exe.dev LLM integration (`exeModel`) — managed, BYO key, or a **ChatGPT / Grok subscription** |
|
|
29
29
|
| Slack/Photon/Linear credentials | Vercel Connect | **Portable/static credentials the client issues** |
|
|
30
30
|
| Sandbox | `vercel()` hosted | `docker()` on the host |
|
|
31
31
|
| File delivery | Vercel Blob | Blob **or** `DELIVER_DIR` + `DELIVER_BASE_URL` |
|
|
@@ -38,6 +38,44 @@ Vercel MCP connection, Linear, everything. Each becomes a static credential
|
|
|
38
38
|
someone must issue and rotate. `kyb doctor` fails loudly if a `@vercel/connect`
|
|
39
39
|
import survives into a self-hosted agent.
|
|
40
40
|
|
|
41
|
+
## Running on the client's own subscription
|
|
42
|
+
|
|
43
|
+
A client who already pays for ChatGPT Plus/Pro or SuperGrok / X Premium+ can
|
|
44
|
+
run the agent on it instead of on metered API billing. Both work the same way:
|
|
45
|
+
a CLI performs a device login on the host, writes a credential to the home
|
|
46
|
+
directory, and that credential is a valid bearer for an OpenAI-compatible
|
|
47
|
+
endpoint. eve ships `experimental_chatgpt()` for the first;
|
|
48
|
+
`@kybernesis/exe` ships `grokSubscription()` for the second.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# on the host, as the user the agent runs as
|
|
52
|
+
curl -fsSL https://x.ai/cli/install.sh | bash
|
|
53
|
+
grok login # device flow → ~/.grok/auth.json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```ts title="agent/agent.ts"
|
|
57
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
58
|
+
import { grokSubscription } from "@kybernesis/exe";
|
|
59
|
+
|
|
60
|
+
export default defineAgent({
|
|
61
|
+
model: grokSubscription({ model: "grok-4.6", createOpenAI }),
|
|
62
|
+
modelContextWindowTokens: 400_000,
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
What this arrangement costs you, and it is worth saying to the client:
|
|
67
|
+
|
|
68
|
+
- **It is per-machine and per-user.** The login belongs to the host's home
|
|
69
|
+
directory. Moving the agent means logging in again; running it as a different
|
|
70
|
+
unix user means it cannot see the credential at all.
|
|
71
|
+
- **The token expires in hours** (Grok: six) and the CLI refreshes it in place.
|
|
72
|
+
Read it per request, never once at boot, or the agent works all afternoon and
|
|
73
|
+
starts failing authentication at dinner for no reason a user can see.
|
|
74
|
+
- **Nobody has proven unattended refresh over days.** If no one runs `grok` on
|
|
75
|
+
that host, whether the refresh keeps happening is an open question — and it
|
|
76
|
+
presents as the agent "breaking".
|
|
77
|
+
- **Ask the vendor's terms question before a client demo**, not after.
|
|
78
|
+
|
|
41
79
|
## The failure modes, each of which cost a real session
|
|
42
80
|
|
|
43
81
|
- **Docker ships disabled on some images.** exe.dev's exeuntu runs
|
|
@@ -144,3 +182,20 @@ yesterday's agent. Assert the process started AFTER the build it should serve
|
|
|
144
182
|
(`scripts/eve-server.sh` and the restart pattern in `@kybernesis/exe` do this).
|
|
145
183
|
Related: a long-lived channel session caches the compiled agent, so start a
|
|
146
184
|
fresh conversation after changing capabilities.
|
|
185
|
+
|
|
186
|
+
A restart script also has to **serialize** (`flock`, released by the child with
|
|
187
|
+
`9>&-`) and **wait for in-flight turns** — eve does not resume a step killed
|
|
188
|
+
mid-flight, and restarting into a live turn strands the session behind a turn
|
|
189
|
+
that will never finish.
|
|
190
|
+
|
|
191
|
+
Run restarts **detached** from your ssh connection —
|
|
192
|
+
`setsid nohup bash restart.sh >/tmp/r.log 2>&1 </dev/null &` — or a dropped
|
|
193
|
+
connection SIGHUPs the script halfway through and leaves exactly the mess it
|
|
194
|
+
exists to prevent.
|
|
195
|
+
|
|
196
|
+
**And measure it correctly.** `pgrep -f 'server/index.mjs'` typed over ssh
|
|
197
|
+
matches the shell running it: the pattern is in that shell's own command line,
|
|
198
|
+
so it reports two servers when there is one. A whole investigation went into a
|
|
199
|
+
phantom "second server" that `ps -eo pid,ppid,args` would have dismissed
|
|
200
|
+
immediately. Inside a script file it is safe; typed at a shell it is not. List
|
|
201
|
+
the matches before you believe the count.
|