@jr2/orchestrator 0.6.0 → 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/console/components/app.ts +55 -15
- package/console/components/bottom-drawer.ts +259 -0
- package/console/components/drawer.ts +14 -6
- package/console/components/fleet.ts +36 -13
- package/console/components/machine-pane.ts +61 -5
- package/console/components/nav.ts +54 -8
- package/console/conversation.ts +161 -0
- package/console/login.ts +123 -0
- package/console/main.ts +600 -60
- package/console/store.ts +611 -64
- package/console/style.css +231 -0
- package/docs/agents-block.md +2 -2
- package/docs/concepts/agents-and-turns.md +86 -9
- package/docs/concepts/architecture.md +41 -28
- package/docs/concepts/callers-and-hooks.md +205 -0
- package/docs/concepts/charts.md +7 -5
- package/docs/concepts/composition.md +10 -1
- package/docs/concepts/converge.md +4 -2
- package/docs/concepts/durable-runs.md +43 -16
- package/docs/concepts/effects.md +50 -22
- package/docs/concepts/gates.md +95 -25
- package/docs/concepts/machines-and-workflows.md +5 -4
- package/docs/concepts/pools-and-sources.md +187 -11
- package/docs/concepts/secrets-and-trust.md +73 -33
- package/docs/concepts/the-menu.md +11 -0
- package/docs/concepts/workspaces.md +6 -5
- package/docs/get-started/a-model-decides.md +14 -13
- package/docs/get-started/an-agent-in-a-sandbox.md +43 -34
- package/docs/get-started/connect-a-model.md +1 -1
- package/docs/get-started/create-an-instance.md +17 -14
- package/docs/guides/add-tools-to-the-sandbox.md +55 -11
- package/docs/guides/answer-a-gate-from-a-forge.md +304 -0
- package/docs/guides/answer-a-gate.md +74 -37
- package/docs/guides/bind-open-parts.md +24 -8
- package/docs/guides/call-an-mcp-tool-from-a-machine.md +572 -0
- package/docs/guides/cancel-a-run.md +26 -16
- package/docs/guides/fix-a-failed-converge.md +18 -6
- package/docs/guides/give-a-caller-a-scope.md +203 -0
- package/docs/guides/give-an-agent-mcp-tools.md +422 -0
- package/docs/guides/iterate-on-a-machine-on-kind.md +10 -9
- package/docs/guides/let-an-agent-write-a-chart.md +9 -6
- package/docs/guides/look-inside-a-sandbox.md +101 -31
- package/docs/guides/open-the-console.md +63 -14
- package/docs/guides/read-a-conversation.md +225 -0
- package/docs/guides/run-a-chart-by-name.md +17 -16
- package/docs/guides/run-one-worker-per-item.md +15 -9
- package/docs/guides/set-an-agents-access-and-dials.md +2 -0
- package/docs/guides/start-a-run-for-each-alert.md +290 -0
- package/docs/guides/start-a-run-from-a-run.md +18 -16
- package/docs/guides/start-a-run.md +24 -18
- package/docs/guides/steer-an-agent.md +332 -0
- package/docs/guides/use-a-hosted-provider.md +1 -1
- package/docs/guides/watch-a-run.md +127 -121
- package/docs/guides/write-a-hook-kind.md +238 -0
- package/docs/guides/write-a-tool-as-an-mcp-server.md +351 -0
- package/docs/guides/write-a-workflow.md +17 -7
- package/docs/llms.txt +81 -15
- package/docs/reference/authoring-surface/agent.md +1 -1
- package/docs/reference/authoring-surface/answer.md +1 -1
- package/docs/reference/authoring-surface/arg.md +1 -1
- package/docs/reference/authoring-surface/basic.md +1 -1
- package/docs/reference/authoring-surface/bearer.md +1 -1
- package/docs/reference/authoring-surface/branchname.md +1 -1
- package/docs/reference/authoring-surface/carry.md +23 -0
- package/docs/reference/authoring-surface/chartschema.md +1 -1
- package/docs/reference/authoring-surface/chartschemafor.md +1 -1
- package/docs/reference/authoring-surface/command.md +1 -1
- package/docs/reference/authoring-surface/customize.md +4 -1
- package/docs/reference/authoring-surface/defineconfig.md +1 -1
- package/docs/reference/authoring-surface/defineevent.md +1 -1
- package/docs/reference/authoring-surface/dispatch.md +5 -4
- package/docs/reference/authoring-surface/fail.md +1 -1
- package/docs/reference/authoring-surface/file.md +1 -1
- package/docs/reference/authoring-surface/frompick.md +1 -1
- package/docs/reference/authoring-surface/gate.md +118 -0
- package/docs/reference/authoring-surface/group-agents.md +15 -0
- package/docs/reference/authoring-surface/group-charts.md +16 -0
- package/docs/reference/authoring-surface/group-composition.md +25 -0
- package/docs/reference/authoring-surface/group-config.md +17 -0
- package/docs/reference/authoring-surface/group-effects.md +48 -0
- package/docs/reference/authoring-surface/group-failure.md +13 -0
- package/docs/reference/authoring-surface/group-gates.md +16 -0
- package/docs/reference/authoring-surface/group-machine-and-events.md +15 -0
- package/docs/reference/authoring-surface/group-steering.md +12 -0
- package/docs/reference/authoring-surface/group-types-these-signatures-name.md +137 -0
- package/docs/reference/authoring-surface/group-workspaces-and-repos.md +15 -0
- package/docs/reference/authoring-surface/http.md +1 -1
- package/docs/reference/authoring-surface/isfailure.md +1 -1
- package/docs/reference/authoring-surface/isready.md +1 -1
- package/docs/reference/authoring-surface/jr2setup.md +13 -3
- package/docs/reference/authoring-surface/mcp.md +107 -0
- package/docs/reference/authoring-surface/open.md +5 -3
- package/docs/reference/authoring-surface/openbody.md +1 -1
- package/docs/reference/authoring-surface/paramsof.md +1 -1
- package/docs/reference/authoring-surface/pool.md +77 -9
- package/docs/reference/authoring-surface/push.md +1 -1
- package/docs/reference/authoring-surface/readyof.md +1 -1
- package/docs/reference/authoring-surface/reread.md +19 -0
- package/docs/reference/authoring-surface/secret.md +1 -1
- package/docs/reference/authoring-surface/sentby.md +1 -1
- package/docs/reference/authoring-surface/skip.md +22 -0
- package/docs/reference/authoring-surface/source.md +56 -1
- package/docs/reference/authoring-surface/steer.md +93 -0
- package/docs/reference/authoring-surface/text.md +1 -1
- package/docs/reference/authoring-surface/type-agentdefinition.md +14 -1
- package/docs/reference/authoring-surface/type-agentmcpserver.md +54 -0
- package/docs/reference/authoring-surface/type-anyframepath.md +1 -1
- package/docs/reference/authoring-surface/type-anyworktreepath.md +1 -1
- package/docs/reference/authoring-surface/type-binding.md +1 -1
- package/docs/reference/authoring-surface/type-caller.md +40 -0
- package/docs/reference/authoring-surface/type-callerrecord.md +32 -0
- package/docs/reference/authoring-surface/type-carry.md +19 -0
- package/docs/reference/authoring-surface/type-chainlink.md +3 -3
- package/docs/reference/authoring-surface/type-commandoutput.md +1 -1
- package/docs/reference/authoring-surface/type-customize.md +16 -1
- package/docs/reference/authoring-surface/type-delivered.md +17 -0
- package/docs/reference/authoring-surface/type-deliveredevent.md +18 -0
- package/docs/reference/authoring-surface/type-dispatchdefinition.md +4 -3
- package/docs/reference/authoring-surface/type-dispatchoutput.md +1 -1
- package/docs/reference/authoring-surface/type-effectbinding.md +12 -2
- package/docs/reference/authoring-surface/type-framepath.md +1 -1
- package/docs/reference/authoring-surface/type-gatebinding.md +15 -0
- package/docs/reference/authoring-surface/type-gatehooks.md +12 -0
- package/docs/reference/authoring-surface/type-gatelook.md +37 -0
- package/docs/reference/authoring-surface/type-gateoutcome.md +32 -0
- package/docs/reference/authoring-surface/type-gatereply.md +19 -0
- package/docs/reference/authoring-surface/type-gateslot.md +21 -0
- package/docs/reference/authoring-surface/type-gateslotinput.md +13 -0
- package/docs/reference/authoring-surface/type-gateslotparts.md +18 -0
- package/docs/reference/authoring-surface/type-gateslots.md +12 -0
- package/docs/reference/authoring-surface/type-gatetypesat.md +13 -0
- package/docs/reference/authoring-surface/type-hostinjectedinput.md +1 -1
- package/docs/reference/authoring-surface/type-httpoutput.md +1 -1
- package/docs/reference/authoring-surface/type-jr2config.md +37 -2
- package/docs/reference/authoring-surface/type-lateroutcome.md +1 -1
- package/docs/reference/authoring-surface/type-lends.md +5 -1
- package/docs/reference/authoring-surface/type-lookoutput.md +14 -0
- package/docs/reference/authoring-surface/type-mcpcalloutput.md +78 -0
- package/docs/reference/authoring-surface/type-mcpnotreturned.md +42 -0
- package/docs/reference/authoring-surface/type-mcpoptions.md +47 -0
- package/docs/reference/authoring-surface/type-mcpoutput.md +50 -0
- package/docs/reference/authoring-surface/type-mcpreadoutput.md +53 -0
- package/docs/reference/authoring-surface/type-mcpremoteserver.md +50 -0
- package/docs/reference/authoring-surface/type-mcpserver.md +41 -0
- package/docs/reference/authoring-surface/type-mcpstdioserver.md +42 -0
- package/docs/reference/authoring-surface/type-namedsecret.md +4 -4
- package/docs/reference/authoring-surface/type-openbodydeclaration.md +1 -1
- package/docs/reference/authoring-surface/type-openbodyoutput.md +1 -1
- package/docs/reference/authoring-surface/type-poolnextinput.md +1 -1
- package/docs/reference/authoring-surface/type-poolspec.md +11 -6
- package/docs/reference/authoring-surface/type-pushoutput.md +1 -1
- package/docs/reference/authoring-surface/type-pushsourcespec.md +38 -0
- package/docs/reference/authoring-surface/type-readsourcespec.md +47 -0
- package/docs/reference/authoring-surface/type-reposlot.md +1 -1
- package/docs/reference/authoring-surface/type-reread.md +18 -0
- package/docs/reference/authoring-surface/type-runsconfig.md +41 -0
- package/docs/reference/authoring-surface/type-sender.md +26 -1
- package/docs/reference/authoring-surface/type-sendercallerfield.md +14 -0
- package/docs/reference/authoring-surface/type-size.md +1 -1
- package/docs/reference/authoring-surface/type-skip.md +19 -0
- package/docs/reference/authoring-surface/type-sourcehooks.md +23 -0
- package/docs/reference/authoring-surface/type-sourcein.md +25 -0
- package/docs/reference/authoring-surface/type-sourcereply.md +18 -0
- package/docs/reference/authoring-surface/type-sourcespec.md +16 -7
- package/docs/reference/authoring-surface/type-sourceverdict.md +49 -0
- package/docs/reference/authoring-surface/type-standingpoolmachine.md +12 -0
- package/docs/reference/authoring-surface/type-standingpoolspec.md +51 -0
- package/docs/reference/authoring-surface/type-steerargs.md +20 -0
- package/docs/reference/authoring-surface/type-thinkinglevel.md +1 -1
- package/docs/reference/authoring-surface/type-usercontainer.md +1 -1
- package/docs/reference/authoring-surface/type-workspaced.md +1 -1
- package/docs/reference/authoring-surface/type-worktreefound.md +3 -3
- package/docs/reference/authoring-surface/type-worktreeinput.md +1 -1
- package/docs/reference/authoring-surface/type-worktreeoptions.md +1 -1
- package/docs/reference/authoring-surface/type-worktreeoutput.md +1 -1
- package/docs/reference/authoring-surface/type-worktreepath.md +1 -1
- package/docs/reference/authoring-surface/type-worktreeready.md +1 -1
- package/docs/reference/authoring-surface/type-worktreerefused.md +4 -4
- package/docs/reference/authoring-surface/workspace.md +1 -1
- package/docs/reference/authoring-surface/worktree.md +1 -1
- package/docs/reference/authoring-surface.md +88 -167
- package/docs/reference/cli.md +413 -74
- package/docs/reference/config.md +235 -2
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +71 -11
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +14 -10
- package/docs/reference/decisions/0006-agent-control-surface.md +4 -4
- package/docs/reference/decisions/0007-durable-machine-state.md +1 -1
- package/docs/reference/decisions/0009-cli-and-instance-interface.md +150 -49
- package/docs/reference/decisions/0010-bdd-acceptance-tests.md +5 -3
- package/docs/reference/decisions/0011-workflow-defined-events.md +256 -12
- package/docs/reference/decisions/0012-workspace-wrapper-machine.md +9 -2
- package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +20 -14
- package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +53 -27
- package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +18 -14
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +226 -12
- package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +15 -7
- package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +32 -18
- package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +14 -1
- package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +4 -4
- package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +116 -34
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +38 -37
- package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +10 -5
- package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +7 -6
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +23 -7
- package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +18 -10
- package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +3 -2
- package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +23 -18
- package/docs/reference/decisions/0032-the-console-unlocks-with-a-callers-credential.md +101 -0
- package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +4 -3
- package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +6 -6
- package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +5 -4
- package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +19 -19
- package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +6 -1
- package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +55 -40
- package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +14 -13
- package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +7 -0
- package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +13 -7
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +38 -30
- package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +64 -17
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +2 -1
- package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +2 -2
- package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-kept-for-a-set-time.md +109 -0
- package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +51 -23
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +94 -54
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +101 -47
- package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +32 -9
- package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +17 -13
- package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +56 -30
- package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +35 -25
- package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +4 -3
- package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +37 -10
- package/docs/reference/decisions/0078-a-caller-comes-from-one-authenticator-seam-and-acts-within-its-scopes.md +285 -0
- package/docs/reference/decisions/0079-an-agent-holds-mcp-tools-a-machine-calls-them-as-an-effect-and-the-machine-is-the-approval.md +198 -0
- package/docs/reference/decisions.md +6 -4
- package/docs/reference/glossary.md +96 -42
- package/docs/reference/hooks.md +1077 -0
- package/docs/reference/http-api.md +976 -149
- package/docs/why.md +2 -1
- package/package.json +10 -3
- package/src/actor.ts +36 -10
- package/src/agent.ts +50 -0
- package/src/assembly-checks.ts +530 -4
- package/src/callers.ts +245 -0
- package/src/chart.ts +52 -7
- package/src/config.ts +550 -1
- package/src/conversations.ts +453 -0
- package/src/custodian.ts +8 -2
- package/src/customize.ts +143 -4
- package/src/dispatch-effect.ts +142 -26
- package/src/durability.ts +2 -0
- package/src/duration.ts +20 -0
- package/src/effect-checks.ts +2 -1
- package/src/effect.ts +60 -7
- package/src/effector-wire.ts +272 -27
- package/src/gate-brand.ts +16 -0
- package/src/gate.ts +634 -48
- package/src/harness-client.ts +10 -4
- package/src/held-secrets.ts +72 -23
- package/src/holds.ts +2 -2
- package/src/hook-kinds/discord.ts +92 -0
- package/src/hook-kinds/door.ts +107 -0
- package/src/hook-kinds/github.ts +89 -0
- package/src/hook-kinds/gitlab.ts +72 -0
- package/src/hook-kinds/hook.ts +7 -0
- package/src/hook-kinds/index.ts +465 -0
- package/src/hook-kinds/slack.ts +151 -0
- package/src/hook-kinds/webhook.ts +113 -0
- package/src/hooks.ts +506 -0
- package/src/http-effect.ts +76 -38
- package/src/http.ts +889 -94
- package/src/index.ts +16 -5
- package/src/instance.ts +196 -26
- package/src/internal.ts +22 -3
- package/src/machine-doc.ts +26 -1
- package/src/mcp-effect.ts +424 -0
- package/src/mount-digest.ts +41 -7
- package/src/names.ts +64 -2
- package/src/notices.ts +138 -10
- package/src/open-body.ts +25 -11
- package/src/open-effect.ts +17 -4
- package/src/open.ts +4 -2
- package/src/parts.ts +87 -9
- package/src/party.ts +2 -1
- package/src/pick.ts +2 -2
- package/src/pool.ts +1142 -163
- package/src/registration.ts +203 -13
- package/src/run-host.ts +1509 -171
- package/src/run-list.ts +191 -0
- package/src/sandbox-kube.ts +53 -5
- package/src/secret-placement.ts +239 -33
- package/src/server.ts +53 -4
- package/src/setup.ts +72 -32
- package/src/snapshot-store.ts +565 -48
- package/src/steer.ts +111 -0
- package/src/stub-harness.ts +6 -2
- package/src/tokens.ts +263 -22
- package/src/wire.ts +17 -0
- package/src/workspace.ts +50 -6
- package/src/worktree.ts +3 -3
- package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +0 -61
- package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +0 -65
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Callers and Hooks
|
|
3
|
+
description: Who acts on an Instance from outside its Machines, what each one may do, and what a Hook does.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Callers and Hooks
|
|
7
|
+
|
|
8
|
+
A [Caller](../reference/glossary.md#caller) is the holder of a credential that acts on an
|
|
9
|
+
[Instance](../reference/glossary.md#instance) from outside its [Machines](../reference/glossary.md#machine). A person, a
|
|
10
|
+
CI job, a bridge to a chat service and an outside service are Callers. A Caller can start a run, read it, answer a
|
|
11
|
+
[Gate](../reference/glossary.md#gate), send a [Steering message](../reference/glossary.md#steering-message) or cancel a
|
|
12
|
+
run, for the [Workflows](../reference/glossary.md#workflow) that its scopes name. A
|
|
13
|
+
[Hook](../reference/glossary.md#hook) is the door of an Instance for one outside service, such as a forge. It is a
|
|
14
|
+
Caller that can only answer a Gate or bring items to a Source. Its [Hook kind](../reference/glossary.md#hook-kind) is
|
|
15
|
+
the protocol of the service.
|
|
16
|
+
|
|
17
|
+
## Why it exists
|
|
18
|
+
|
|
19
|
+
One Instance token can do everything on each run. A CI job that starts runs, a bridge that answers Gates, and a teammate
|
|
20
|
+
with a browser need less than that. If each one holds the Instance token, each one can do each act on each run, and the
|
|
21
|
+
run cannot say who acted. Thus jr2 knows each Caller by its credential, gives it only its scopes, and records it on each
|
|
22
|
+
act.
|
|
23
|
+
|
|
24
|
+
An outside service sends a delivery, such as a review on a forge. It does not send a bearer token, and each service has
|
|
25
|
+
its own signature, its own body and its own handshake. A Hook checks that a delivery comes from its service, and decides
|
|
26
|
+
nothing. The Gate or the Source that hears it decides what the delivery means for its run.
|
|
27
|
+
|
|
28
|
+
## How a Caller is known
|
|
29
|
+
|
|
30
|
+
The Orchestrator has an ordered list of authenticators. Each one looks at the credential of a request. It gives a
|
|
31
|
+
Caller, or it says that the credential is not its credential. The first one that claims the credential decides. When it
|
|
32
|
+
finds the credential bad, the answer is 401, and the next authenticator does not look at it. A credential that no
|
|
33
|
+
authenticator claims also gets 401.
|
|
34
|
+
|
|
35
|
+
| Authenticator | The credential | The Caller |
|
|
36
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
|
|
37
|
+
| Instance token | The token in the `jr2-instance` Secret. The CLI reads it over the Kubernetes API. | `token/instance`, with each scope for each Workflow |
|
|
38
|
+
| Named token | A value that starts with `jr2c_`, for a name in [`callers.tokens`](../reference/config.md#callers-tokens) | `token/<name>`, with the scopes of its entry |
|
|
39
|
+
| JWT | A JWT of an issuer in [`callers.issuers`](../reference/config.md#callers-issuers) | `jwt/<sub>`, with the scopes that its groups give |
|
|
40
|
+
| A Hook's verifier | A delivery at `POST /hooks/<name>`, with no bearer token | `hook/<name>`, with `answer` only |
|
|
41
|
+
|
|
42
|
+
The tokens of a Sandbox and the publish token are not Callers, and no authenticator makes a Caller from them. Thus an
|
|
43
|
+
Agent cannot answer a Gate. [Secrets and trust](secrets-and-trust.md#the-tokens) tells where each token is kept.
|
|
44
|
+
|
|
45
|
+
For a JWT, jr2 checks the signature with the published keys of the issuer, and the issuer, the audience and the expiry.
|
|
46
|
+
The name of the Caller is the `sub` claim, and the name that jr2 shows is the `email` claim. The `groups` map of the
|
|
47
|
+
issuer entry gives scopes for the values of a claim, such as the groups of a person. A JWT that gets no scope from the
|
|
48
|
+
map can do nothing. An issuer with `login: true` also lets a person log in to the
|
|
49
|
+
[Console](../reference/glossary.md#console) ([Open the Console](../guides/open-the-console.md#log-in)).
|
|
50
|
+
|
|
51
|
+
[`jr2 whoami`](../reference/cli.md#whoami) and [`GET /whoami`](../reference/http-api.md#get-whoami) show the Caller of a
|
|
52
|
+
credential, with its scopes. Use them to see what a credential can do before a request fails.
|
|
53
|
+
|
|
54
|
+
## Scopes
|
|
55
|
+
|
|
56
|
+
A scope is one act of a Caller. Its value is `"all"`, or a list of the names of the Workflows that it opens:
|
|
57
|
+
|
|
58
|
+
| Scope | The act |
|
|
59
|
+
| -------- | ----------------------------------------------------------------------------------------- |
|
|
60
|
+
| `start` | Start a run. |
|
|
61
|
+
| `read` | Read the full state of a run, follow its feed, list the runs, and read its conversations. |
|
|
62
|
+
| `answer` | Answer a Gate, and read the open Gates and their meta. |
|
|
63
|
+
| `cancel` | Cancel a run. |
|
|
64
|
+
| `steer` | Send a Steering message to an Agent of a run. |
|
|
65
|
+
|
|
66
|
+
For a route that addresses a run, jr2 checks the scope against the Workflow of that run. The name of a Chart wrapper
|
|
67
|
+
also opens each named Chart of that wrapper. A request without the scope gets 403, which names the scope and the
|
|
68
|
+
Workflow. [`GET /runs`](../reference/http-api.md#get-runs) shows only the runs of the Workflows that the Caller can
|
|
69
|
+
read. A few routes, such as a runtime Chart and the log of a Hook, need the Instance token: no scope opens them. The
|
|
70
|
+
[HTTP API](../reference/http-api.md#band-guarded) gives the scope of each route.
|
|
71
|
+
|
|
72
|
+
The `answer` scope can also name single Gates of a Workflow, with an item `{ workflow, gates }` beside the names of
|
|
73
|
+
Workflows. The name of a Gate is its invoke id. A Caller with such an item answers only those Gates of that Workflow,
|
|
74
|
+
and it sees only those Gates, in [`GET /gates`](../reference/http-api.md#get-gates) and in `GET /runs/:runId`. A gate
|
|
75
|
+
POST to another open Gate of that Workflow gets 403, which names the scope, the Workflow and the Gate. `jr2 up` refuses
|
|
76
|
+
a Gate name that the Machines of the Workflow do not have. The other scopes, and the `may.answer` of a Hook, name only
|
|
77
|
+
Workflows.
|
|
78
|
+
|
|
79
|
+
A scope does not limit what a run does. A run that a Caller starts can start a run of a different Workflow with a
|
|
80
|
+
[`dispatch`](../reference/authoring-surface/dispatch.md) Effect. The Machine is the limit of what its run does.
|
|
81
|
+
|
|
82
|
+
## On behalf of
|
|
83
|
+
|
|
84
|
+
A Caller can say that it acts on behalf of a different party, in the header `jr2-on-behalf-of`. The CLI sends the name
|
|
85
|
+
of your Kubernetes user. A bridge can send the name of the person in the chat service. jr2 records this name and shows
|
|
86
|
+
it, but it does not check it. The one exception is a Hook: the name comes from the body of the delivery, and the
|
|
87
|
+
signature of the service covers the body.
|
|
88
|
+
|
|
89
|
+
## The record of each act
|
|
90
|
+
|
|
91
|
+
The run records the Caller of each act on a guarded route: its `via`, its `name`, the name that jr2 shows, and
|
|
92
|
+
`onBehalfOf`. It does not record the scopes.
|
|
93
|
+
|
|
94
|
+
- `startedBy`: the Caller that started the run. A run that a local `dispatch` started records that run and the slot. A
|
|
95
|
+
run that jr2 started, such as the run of a standing Pool, records `jr2` and why: `boot`, `publish`, `hand-over` or
|
|
96
|
+
`resume`.
|
|
97
|
+
- `cancelledBy`: the Caller that cancelled the run.
|
|
98
|
+
- `answers`: the last 100 answers to the Gates of the run, each with the Caller that answered.
|
|
99
|
+
|
|
100
|
+
The [Sender](../reference/glossary.md#sender) of an event that a Gate delivers also holds the Caller, and `checked`
|
|
101
|
+
names the fields of it that jr2 checked. [`jr2 status`](../reference/cli.md#status) follows `startedBy` from run to run,
|
|
102
|
+
to the first Caller, and prints it as `started by:`. The open routes do not show these records.
|
|
103
|
+
|
|
104
|
+
## How a Hook behaves
|
|
105
|
+
|
|
106
|
+
The `hooks` block of `jr2.config.ts` declares each Hook by its name, with its kind. The address of the Hook is
|
|
107
|
+
`POST /hooks/<name>`. The kind makes the Hook from two things: the credential, and `may.answer`, the Workflows whose
|
|
108
|
+
Gates the Hook can answer. The default is every Workflow. A Hook never starts a run. To bring items to a
|
|
109
|
+
[Pool](../reference/glossary.md#pool), it answers the `source` Gate of the Pool, so `may.answer` must name the Workflow
|
|
110
|
+
of the Pool.
|
|
111
|
+
|
|
112
|
+
**One delivery at a Hook**
|
|
113
|
+
|
|
114
|
+
- **Service**: a forge or a chat service
|
|
115
|
+
- **Door**: the Hook's address in the Orchestrator
|
|
116
|
+
- **Instance Effector**: holds a mac secret
|
|
117
|
+
- **Kind**: the protocol of the service
|
|
118
|
+
- **Handlers**: of the open Gates and Sources
|
|
119
|
+
- Service → Door: a delivery
|
|
120
|
+
- Door → Instance Effector: the signed bytes, for mac only
|
|
121
|
+
- Instance Effector → Door: match, or no match
|
|
122
|
+
- Door → Kind: the request, without a token header
|
|
123
|
+
- Kind → Door: a handshake, or the event key, the id and the payload
|
|
124
|
+
- Door → Handlers: the parsed payload
|
|
125
|
+
- Door → Service: the outcome, or a text for a person
|
|
126
|
+
|
|
127
|
+
The door does the same steps for each kind:
|
|
128
|
+
|
|
129
|
+
1. **It verifies the delivery.** The kind tells what the service signed. The door runs one of three verifiers:
|
|
130
|
+
- `mac`: a shared secret signs the bytes, such as on GitHub and Slack. The
|
|
131
|
+
[Instance Effector](../reference/glossary.md#instance-effector) holds the secret, and it answers only "match" or
|
|
132
|
+
"no match". The Orchestrator never holds the secret, because a secret that verifies a delivery can also make one.
|
|
133
|
+
- `token`: the service sends a shared token in a header, such as on GitLab. The Orchestrator keeps only the SHA-256
|
|
134
|
+
digest of the token, and removes the header before the kind reads the request.
|
|
135
|
+
- `ed25519`: a key pair signs the delivery, such as on Discord. The config holds the public key, which cannot sign.
|
|
136
|
+
|
|
137
|
+
When the service signs a time, the door refuses a time that is more than 300 seconds from its clock. A delivery that
|
|
138
|
+
fails gets 401, and nothing more occurs.
|
|
139
|
+
|
|
140
|
+
Before the verifier, the door refuses a body that is larger than 2 MiB with 413. It reads no more of the body than
|
|
141
|
+
this limit.
|
|
142
|
+
|
|
143
|
+
2. **The kind reads the delivery.** A handshake, such as a GitHub `ping`, gets the answer of the kind, and goes to no
|
|
144
|
+
Gate. Otherwise the kind gives the event key, the id of the delivery, `onBehalfOf` and the payload.
|
|
145
|
+
3. **The schema of the event key parses the payload.** A payload that the schema refuses goes to no Gate.
|
|
146
|
+
4. **The door looks for a repeat.** A delivery whose id or body the Hook got before goes to no Gate. The door does this
|
|
147
|
+
check after the parse, so a payload that the schema refused is parsed again when the service sends it again.
|
|
148
|
+
5. **The delivery goes to each handler that hears it**: each open Gate and each Source, in each live run of a Workflow
|
|
149
|
+
that the Hook can answer, whose handlers name the kind and the event key. [Gates](gates.md#a-gate-that-hears-a-hook)
|
|
150
|
+
and [Pools and Sources](pools-and-sources.md#a-hook-reaches-a-source) tell what a handler gives.
|
|
151
|
+
|
|
152
|
+
The answer is the outcome of the delivery, as JSON: where it went, and what each Gate or Source did with it. For a chat
|
|
153
|
+
command or a click, the person who acted reads one text in the envelope of the kind
|
|
154
|
+
([The answer that a person reads](gates.md#the-answer-that-a-person-reads)).
|
|
155
|
+
|
|
156
|
+
The log of the Hook keeps each delivery and its outcome for `runs.retain`, 30 days by default. The repeat check reads
|
|
157
|
+
it. Print it with [`jr2 hooks <name>`](../reference/cli.md#hooks).
|
|
158
|
+
|
|
159
|
+
## Hook kinds
|
|
160
|
+
|
|
161
|
+
A Hook kind is code that `jr2.config.ts` imports. It tells what the service signed, how to read a delivery and its
|
|
162
|
+
payloads, the handshake of the service, and the envelope of a text that a person reads. A workflow module imports the
|
|
163
|
+
same kind for the types of its handlers. Thus a handler for an event key that the kind does not give does not compile.
|
|
164
|
+
|
|
165
|
+
- `@jr2/orchestrator/hooks` ships the kinds `github`, `gitlab`, `slack` and `discord`.
|
|
166
|
+
- [`webhook()`](../reference/hooks.md#webhook) makes a kind from data, for a service that sends JSON, signs only the
|
|
167
|
+
body, and has no handshake.
|
|
168
|
+
- [`defineHookKind()`](../reference/hooks.md#definehookkind) makes a kind for any other service, in a module of the
|
|
169
|
+
Instance or in a package of its own.
|
|
170
|
+
|
|
171
|
+
A kind never gets the credential: jr2 makes the constructor of the kind, so the credential goes from the config to the
|
|
172
|
+
door. A kind is pure and synchronous. It does no I/O, and it does not read a clock. The door does the verify, the time
|
|
173
|
+
window, the repeat check and the follow-up post. When a kind gives a follow-up post, such as the reply to a Slack click,
|
|
174
|
+
it declares the hosts of its posts, and `jr2 up` adds them to the targets of the Instance Effector.
|
|
175
|
+
|
|
176
|
+
## Rules
|
|
177
|
+
|
|
178
|
+
- The first authenticator that claims a credential decides. A credential that it finds bad gets 401.
|
|
179
|
+
- A Sandbox token, a control token and the publish token are not Callers.
|
|
180
|
+
- A request without the scope for the Workflow gets 403. A JWT that gets no scope gets 403 on each route that needs a
|
|
181
|
+
scope.
|
|
182
|
+
- `onBehalfOf` is a claim. jr2 checks it only for a Hook, where the signature covers it.
|
|
183
|
+
- A named token's value is in a Secret of its own. The Orchestrator keeps only its SHA-256 digest.
|
|
184
|
+
- `cors` lists the origins of the browser apps on a different origin that can call the Orchestrator. The Console needs
|
|
185
|
+
no entry.
|
|
186
|
+
- A Hook can only answer a Gate or bring items to a Source, of the Workflows in its `may.answer`. It never starts a run.
|
|
187
|
+
- The door refuses a signed time that is more than 300 seconds from its clock. No config changes the window.
|
|
188
|
+
- Two kinds with one id fail the typecheck and `jr2 up`.
|
|
189
|
+
|
|
190
|
+
## Read next
|
|
191
|
+
|
|
192
|
+
- [Give a Caller a scope](../guides/give-a-caller-a-scope.md)
|
|
193
|
+
- [Answer a Gate from a forge](../guides/answer-a-gate-from-a-forge.md)
|
|
194
|
+
- [Start a run for each alert](../guides/start-a-run-for-each-alert.md)
|
|
195
|
+
- [Write a Hook kind](../guides/write-a-hook-kind.md)
|
|
196
|
+
- [Open the Console](../guides/open-the-console.md)
|
|
197
|
+
- [Secrets and trust](secrets-and-trust.md), [Gates](gates.md) and [Pools and Sources](pools-and-sources.md)
|
|
198
|
+
- Reference: [`callers`](../reference/config.md#callers), [`hooks`](../reference/config.md#hooks),
|
|
199
|
+
[`cors`](../reference/config.md#cors), [`@jr2/orchestrator/hooks`](../reference/hooks.md),
|
|
200
|
+
[`jr2 whoami`](../reference/cli.md#whoami), [`jr2 hooks`](../reference/cli.md#hooks), and the
|
|
201
|
+
[HTTP API](../reference/http-api.md)
|
|
202
|
+
- [ADR-0078](../reference/decisions/0078-a-caller-comes-from-one-authenticator-seam-and-acts-within-its-scopes.md): the
|
|
203
|
+
Callers, the scopes, the Hooks and the Hook kinds
|
|
204
|
+
- [ADR-0014](../reference/decisions/0014-observation-is-open-run-state-is-not.md): which scope opens which route
|
|
205
|
+
- [ADR-0011](../reference/decisions/0011-workflow-defined-events.md): a Gate hears a Hook
|
package/docs/concepts/charts.md
CHANGED
|
@@ -30,9 +30,11 @@ it bad text.
|
|
|
30
30
|
[Open](../reference/glossary.md#open) part that a run binds, not a composer. Its declaration has three parts:
|
|
31
31
|
|
|
32
32
|
- **`lends`**: the parts of the Chart wrapper that a Chart can use, by their slot keys. These are Agents, Effects,
|
|
33
|
-
Machines, guards, actions and delays. `gate: true` lends the
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
Machines, Gate slots (`gates`), guards, actions and delays. `gate: true` lends the
|
|
34
|
+
[Gate](../reference/glossary.md#gate), so that a Chart can wait for a person. A lent Gate slot hears a
|
|
35
|
+
[Hook](../reference/glossary.md#hook), and the door refuses a Chart whose `events` do not hold each event of the
|
|
36
|
+
slot's `delivers`. `fail: true` lends [`fail()`](../reference/authoring-surface/fail.md), so that a Chart can end its
|
|
37
|
+
run as a [Failure](../reference/glossary.md#failure) with `invoke: { src: "fail", input: { reason } }`.
|
|
36
38
|
- **`allows`**: what the Agents that a Chart adds can have. `models` lists the models, and `workspace` lists the
|
|
37
39
|
Workspace accesses. With no model, a Chart cannot add an Agent.
|
|
38
40
|
- **`ceilings`**: the limits of one Chart: the Agent Turns, the wall clock, the transitions, the children at one time,
|
|
@@ -107,8 +109,8 @@ wrapper only. It comes from one of two places:
|
|
|
107
109
|
- A **runtime Chart**: `PUT /workflows/<wrapper>/charts/<name>`, with the Instance token. The Orchestrator keeps it on
|
|
108
110
|
its volume. `DELETE` on the same path removes it.
|
|
109
111
|
|
|
110
|
-
[`jr2
|
|
111
|
-
runtime Chart uses, the Chart stays, and it is unrunnable until a publish gives the part back.
|
|
112
|
+
[`jr2 workflows`](../reference/cli.md#workflows) lists each named Chart under its wrapper. When a publish removes a part
|
|
113
|
+
that a runtime Chart uses, the Chart stays, and it is unrunnable until a publish gives the part back.
|
|
112
114
|
|
|
113
115
|
## A run keeps its Chart
|
|
114
116
|
|
|
@@ -250,7 +250,7 @@ show.
|
|
|
250
250
|
| Key | What it changes |
|
|
251
251
|
| ----------- | ------------------------------------------------------------------------------------- |
|
|
252
252
|
| `agents` | The definition of an Agent, by slot, field by field. `{ model }` keeps the rest. |
|
|
253
|
-
| `effects` | The Open url, argv or
|
|
253
|
+
| `effects` | The Open url, argv, secret, MCP server or tool of an Effect, by slot. |
|
|
254
254
|
| `actors` | A Machine that this Machine composes, by slot. The value has the same keys, one down. |
|
|
255
255
|
| `repos` | The Repo Slots of the [`workspace()`](../reference/authoring-surface/workspace.md). |
|
|
256
256
|
| `image` | The Sandbox Image of the `workspace()`. |
|
|
@@ -272,6 +272,7 @@ A Machine marks a part Open with [`open`](../reference/authoring-surface/open.md
|
|
|
272
272
|
- a Repo Slot with no url, or the whole Repo Slot map (`repos: open`)
|
|
273
273
|
- the model of an Agent (`agent({ model: open, … })`)
|
|
274
274
|
- the url of an `http` Effect, the argv of a `command`, or the name of the secret of an Effect (`secret(open)`)
|
|
275
|
+
- the server or the tool of an `mcp` Effect (`mcp.call(open, open, { input })`)
|
|
275
276
|
|
|
276
277
|
An Open part has no default. You bind it with `customize()`. Each Open part has two checks:
|
|
277
278
|
|
|
@@ -280,6 +281,14 @@ An Open part has no default. You bind it with `customize()`. Each Open part has
|
|
|
280
281
|
- At run time, the part refuses too. An Agent does not start a [Turn](../reference/glossary.md#turn) with an Open model.
|
|
281
282
|
An Effect does not run while it is Open.
|
|
282
283
|
|
|
284
|
+
One Open part only warns: the look of a Gate slot (`look: open`). `jr2 up` prints a warning for a look that nobody
|
|
285
|
+
bound, because a person can still answer the Gate with `jr2 send`.
|
|
286
|
+
|
|
287
|
+
The MCP servers of an Agent are not Open. A packaged Machine's Agent names the servers that it needs, such as
|
|
288
|
+
`slack-acme`. When the `mcp` block of your `jr2.config.ts` does not declare that name, `jr2 up` refuses the Workflow and
|
|
289
|
+
prints the `customize()` line that binds the Agent to a server that you declare:
|
|
290
|
+
`customize(machine, { agents: { <slot>: { mcp: [...] } } })`. The list replaces the Agent's whole `mcp` list.
|
|
291
|
+
|
|
283
292
|
[Bind a shipped Machine's Open parts](../guides/bind-open-parts.md) shows each binding.
|
|
284
293
|
|
|
285
294
|
## @jr2/machines
|
|
@@ -40,7 +40,7 @@ The diagram shows what `jr2 up` makes, and what [`jr2 run`](../reference/cli.md#
|
|
|
40
40
|
- **Assembly**: your Workflows and your config
|
|
41
41
|
- **jr2-instance Secret**: holds the Instance token
|
|
42
42
|
- **Instance Harness**: when an Agent is Menu-only
|
|
43
|
-
- **Instance Effector**: when an Effect runs there
|
|
43
|
+
- **Instance Effector**: when an Effect runs there, or a Hook needs it
|
|
44
44
|
- **Repo cache**: when a Machine has a Sandbox
|
|
45
45
|
- ↓ the Orchestrator asks for each Sandbox · ↑ the operator makes its pod
|
|
46
46
|
- **jr2-system**: one for each cluster
|
|
@@ -79,7 +79,9 @@ the cluster, see [Architecture](architecture.md).
|
|
|
79
79
|
Until each check passes, `jr2 up` writes nothing that the Instance or the operator reads. The pod has up to 5
|
|
80
80
|
minutes to start, and each model has up to 6 minutes. `jr2 up` writes each model's result as it comes. With
|
|
81
81
|
`--skip-provider-preflight`, no pod checks the models, and `jr2 up` writes a warning that names each model that it
|
|
82
|
-
did not check.
|
|
82
|
+
did not check. The same pod asks each remote MCP server that an Agent names for its tools, through its Custodian.
|
|
83
|
+
`jr2 up` refuses an allowlisted tool that the server does not list, and a server that refuses the token. The flag
|
|
84
|
+
skips this check too.
|
|
83
85
|
12. It applies the operator. For a Repo with an ssh url, it asks where the deploy key comes from.
|
|
84
86
|
13. It applies the Secrets and the Orchestrator, and waits for the rollout. When the Machines need them, it also waits
|
|
85
87
|
for the Repo cache, the Instance Harness and the [Instance Effector](../reference/glossary.md#instance-effector).
|
|
@@ -7,7 +7,8 @@ description: How a run survives a restart of the Orchestrator, what ends it, and
|
|
|
7
7
|
|
|
8
8
|
A run is durable. The [Orchestrator](../reference/glossary.md#orchestrator) saves each run after each transition of its
|
|
9
9
|
[Machine](../reference/glossary.md#machine). When the Orchestrator starts again, it continues each run that did not end,
|
|
10
|
-
from the state that it saved. A run that ended stays readable for
|
|
10
|
+
from the state that it saved. A run that ended stays readable for [`runs.retain`](../reference/config.md#runs), 30 days
|
|
11
|
+
by default.
|
|
11
12
|
|
|
12
13
|
## Why runs are durable
|
|
13
14
|
|
|
@@ -78,7 +79,7 @@ A run that the Orchestrator does not continue gets one of these results:
|
|
|
78
79
|
|
|
79
80
|
| Result | When | What stays |
|
|
80
81
|
| --------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
81
|
-
| `lost` | No Workflow has the name of the run's file, or the row holds no snapshot. | The row and the reason, for
|
|
82
|
+
| `lost` | No Workflow has the name of the run's file, or the row holds no snapshot. | The row and the reason, for `runs.retain`. |
|
|
82
83
|
| `drifted` | The Orchestrator cannot read the Assembly of the run, or the Machine of the Workflow has a different shape. | The row and the snapshot. |
|
|
83
84
|
| `failed` | The restore of the run stopped with an error. | The run stays live. The next start tries it again. |
|
|
84
85
|
|
|
@@ -112,8 +113,9 @@ Orchestrator cannot read the Assembly that the run holds:
|
|
|
112
113
|
|
|
113
114
|
The Orchestrator keeps a drifted run, and you can read it. [`jr2 status`](../reference/cli.md#status) shows its status,
|
|
114
115
|
`drifted`, with the reason. The reason names the Workflow and the two digests, or the Assembly and why it cannot load.
|
|
115
|
-
[`jr2 runs`](../reference/cli.md#runs)
|
|
116
|
-
|
|
116
|
+
By default, [`jr2 runs`](../reference/cli.md#runs) shows only the live runs, so it does not show a drifted run.
|
|
117
|
+
`jr2 runs --status drifted`, `--status ended` or `--status all` shows it with its reason. jr2 cannot move a drifted run
|
|
118
|
+
to a new Machine. Thus, before you change the Kit version, let the runs end, or cancel them.
|
|
117
119
|
|
|
118
120
|
## CANCEL and stop
|
|
119
121
|
|
|
@@ -137,18 +139,40 @@ The operator removes them after the same idle timeout. A run that a Machine fail
|
|
|
137
139
|
|
|
138
140
|
`jr2 status` shows a cancelled run with the status `cancelled` and the state that it was in.
|
|
139
141
|
|
|
140
|
-
##
|
|
142
|
+
## History
|
|
141
143
|
|
|
142
|
-
jr2 keeps the row of a run that ended for
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
jr2 keeps the row of a run that ended for 30 days after its last write. `runs.retain` in `jr2.config.ts` changes this
|
|
145
|
+
time, for example `runs: { retain: "90d" }`. It is a number and `m`, `h`, `d` or `w`, and it is at least `1h`. This is
|
|
146
|
+
true for each status that is not live: `done`, `failed`, `error`, `cancelled`, `lost` and `drifted`. The Orchestrator
|
|
147
|
+
deletes the older rows when it starts, and one time each hour after that. A live run stays, whatever its age. A run that
|
|
148
|
+
waits at a Gate for a month is still there.
|
|
146
149
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
`jr2 runs --status ended` lists the runs that ended, newest first. `--workflow` and `--since` make the list shorter. jr2
|
|
151
|
+
is not the record of the results of a run. A Machine sends its results where they belong, such as a pull request.
|
|
152
|
+
`jr2 status` on a run that ended is for debugging. After `runs.retain`, `jr2 status` says that the run does not exist,
|
|
153
|
+
and a prefix of its id no longer finds it.
|
|
150
154
|
|
|
151
|
-
The
|
|
155
|
+
The time of a drifted run starts at the restart or the publish that refused it, not at its last transition.
|
|
156
|
+
|
|
157
|
+
The same time applies to the [Conversations](../reference/glossary.md#conversation) of a run and to the log of each
|
|
158
|
+
[Hook](../reference/glossary.md#hook). The Orchestrator keeps each conversation of an Agent while the run is kept, and
|
|
159
|
+
deletes it with the row of the run. Thus `jr2 logs` reads the conversations of a run that ended, also after its
|
|
160
|
+
[Sandbox](../reference/glossary.md#sandbox) is gone. [Read a conversation](../guides/read-a-conversation.md) gives the
|
|
161
|
+
commands.
|
|
162
|
+
|
|
163
|
+
### The state volume
|
|
164
|
+
|
|
165
|
+
The Orchestrator keeps the rows of the runs, the conversations, the Assemblies and the
|
|
166
|
+
[Charts](../reference/glossary.md#chart) on its state volume. A new volume claim is `5Gi` by default, and `jr2 up` keeps
|
|
167
|
+
the size of a claim that exists. `runs.volume` in `jr2.config.ts` sets its size, such as `runs: { volume: "20Gi" }`.
|
|
168
|
+
`jr2 up` makes the claim larger when its StorageClass allows expansion, and refuses otherwise. It never makes a claim
|
|
169
|
+
smaller, because Kubernetes cannot.
|
|
170
|
+
|
|
171
|
+
A space guard keeps the volume from becoming full. When the volume is more than 80% full, the Orchestrator deletes the
|
|
172
|
+
conversations of the runs that ended, the oldest run first, until the volume is less than 80% full. The rows of the runs
|
|
173
|
+
stay, and each one shows that its conversations went for space. The guard never deletes a conversation of a live run.
|
|
174
|
+
When the volume is more than 95% full and no ended run has a conversation left, the Orchestrator keeps no more entries
|
|
175
|
+
of the open conversations. One conversation also has a limit of 8 MiB, after which the Orchestrator keeps no more of it.
|
|
152
176
|
|
|
153
177
|
[`jr2 down`](../reference/cli.md#down) deletes the namespace of the Instance, and the store with it. The live runs go
|
|
154
178
|
too.
|
|
@@ -162,7 +186,9 @@ too.
|
|
|
162
186
|
- The Orchestrator never continues a drifted run, and never moves it to a new Machine.
|
|
163
187
|
- The Orchestrator never continues a cancelled run.
|
|
164
188
|
- `CANCEL` is the only run event that `jr2 send` sends without `--gate`. `--keep` goes only with `CANCEL`.
|
|
165
|
-
- jr2 keeps a run that ended for
|
|
189
|
+
- jr2 keeps a run that ended for `runs.retain`, 30 days by default. The hourly sweep never deletes a live run.
|
|
190
|
+
- jr2 keeps the conversations of a run for as long as it keeps the run, unless the space guard deletes them first. The
|
|
191
|
+
space guard never deletes a conversation of a live run.
|
|
166
192
|
|
|
167
193
|
[Cancel a run](../guides/cancel-a-run.md) and [Watch a run](../guides/watch-a-run.md) give the commands and their
|
|
168
194
|
output.
|
|
@@ -170,6 +196,7 @@ output.
|
|
|
170
196
|
## Read next
|
|
171
197
|
|
|
172
198
|
- [Watch a run](../guides/watch-a-run.md)
|
|
199
|
+
- [Read a conversation](../guides/read-a-conversation.md)
|
|
173
200
|
- [Cancel a run](../guides/cancel-a-run.md)
|
|
174
201
|
- [Iterate on a Machine on kind](../guides/iterate-on-a-machine-on-kind.md)
|
|
175
202
|
- [Effects](effects.md), [Workspaces](workspaces.md) and [Converge](converge.md)
|
|
@@ -183,7 +210,7 @@ output.
|
|
|
183
210
|
- [ADR-0025](../reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md): `CANCEL` ends a run, and a stop parks it
|
|
184
211
|
- [ADR-0030](../reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md): a snapshot names the
|
|
185
212
|
Machine that wrote it
|
|
186
|
-
- [ADR-0065](../reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-
|
|
187
|
-
and jr2 keeps
|
|
213
|
+
- [ADR-0065](../reference/decisions/0065-a-persist-survives-a-crash-and-history-is-kept-for-a-set-time.md): a save
|
|
214
|
+
survives a crash, and jr2 keeps history for `runs.retain`
|
|
188
215
|
- [ADR-0069](../reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md): a
|
|
189
216
|
run holds the Assembly that it started under
|
package/docs/concepts/effects.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Effects
|
|
3
|
-
description: How a Machine runs a command, calls a URL, pushes a branch or starts a run
|
|
3
|
+
description: How a Machine runs a command, calls a URL or an MCP tool, pushes a branch or starts a run.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Effects
|
|
7
7
|
|
|
8
8
|
An [Effect](../reference/glossary.md#effect) is work that a [Machine](../reference/glossary.md#machine) does outside
|
|
9
|
-
itself. jr2 has
|
|
10
|
-
calls a URL, `push` pushes the branch of a [Worktree](../reference/glossary.md#worktree),
|
|
11
|
-
|
|
9
|
+
itself. jr2 has five kinds: `command` runs a program in the [Workspace](../reference/glossary.md#workspace), `http`
|
|
10
|
+
calls a URL, `push` pushes the branch of a [Worktree](../reference/glossary.md#worktree), `dispatch` starts a run of a
|
|
11
|
+
[Workflow](../reference/glossary.md#workflow), and `mcp` calls a tool of an MCP server. The Kit also gives
|
|
12
12
|
[`worktree()`](../reference/authoring-surface/worktree.md), an Effect on the `command` machinery that cuts a Worktree.
|
|
13
13
|
You write an Effect as an actor slot, beside the [Agents](../reference/glossary.md#agent) of the Machine.
|
|
14
14
|
|
|
@@ -293,7 +293,7 @@ failures: workflow "test-and-push" — the states that fail the run (ADR-0073)
|
|
|
293
293
|
test-and-push.lost: invokes fail
|
|
294
294
|
```
|
|
295
295
|
|
|
296
|
-
## The
|
|
296
|
+
## The five kinds
|
|
297
297
|
|
|
298
298
|
### `command`
|
|
299
299
|
|
|
@@ -483,8 +483,9 @@ Worktree is, and [Cut a Worktree](../guides/cut-a-worktree.md) tells how to use
|
|
|
483
483
|
[`dispatch`](../reference/authoring-surface/dispatch.md) starts a run of a Workflow. The new run is a run of its own: it
|
|
484
484
|
has its own line in [`jr2 runs`](../reference/cli.md#runs), its own Workspaces and its own `CANCEL`. Its record names
|
|
485
485
|
the run that started it: it is **dispatched by** that run. Use `dispatch` when a Machine waits for work, for example at
|
|
486
|
-
a [Gate](../reference/glossary.md#gate) that a
|
|
487
|
-
have. To use a Machine as a part of one run, invoke it in the run instead (see
|
|
486
|
+
a [Gate](../reference/glossary.md#gate) that a [Hook](../reference/glossary.md#hook) answers, and each item of work
|
|
487
|
+
needs a run of a Workflow that you have. To use a Machine as a part of one run, invoke it in the run instead (see
|
|
488
|
+
[Composition](composition.md)).
|
|
488
489
|
|
|
489
490
|
- The name of the Workflow is a constant of the definition, as `jr2 run` writes it: `"triage"`, or `"<wrapper>/<name>"`
|
|
490
491
|
for a named [Chart](../reference/glossary.md#chart). An Agent cannot choose it.
|
|
@@ -496,12 +497,27 @@ have. To use a Machine as a part of one run, invoke it in the run instead (see [
|
|
|
496
497
|
minutes with `wait`.
|
|
497
498
|
- With no `target`, the new run starts in the same Orchestrator. With
|
|
498
499
|
`target: { url: "https://<host>", token: secret("<name>") }`, it starts on a different Orchestrator. `url` is the
|
|
499
|
-
origin of that Orchestrator, and the secret holds
|
|
500
|
+
origin of that Orchestrator, and the secret holds the token of a [Caller](../reference/glossary.md#caller) of that
|
|
501
|
+
Orchestrator with the `start` scope for the Workflow, and also `read` when `wait` is `true`.
|
|
500
502
|
- The new run starts under the current [Assembly](../reference/glossary.md#assembly), as a run of `jr2 run` does.
|
|
501
503
|
|
|
502
504
|
The two runs are independent. A `CANCEL` of one run does not cancel the other. When the run that dispatched ends, the
|
|
503
505
|
new run continues.
|
|
504
506
|
|
|
507
|
+
### `mcp`
|
|
508
|
+
|
|
509
|
+
[`mcp`](../reference/authoring-surface/mcp.md) calls an MCP server: `mcp.call(server, tool, { input })` calls a tool,
|
|
510
|
+
`mcp.read(server, uri)` reads a resource, and `mcp.prompt(server, name, { input })` gets a prompt. `server` is a name of
|
|
511
|
+
the [`mcp`](../reference/config.md#mcp) block of `jr2.config.ts`, which holds the URL and the secret of the server. Thus
|
|
512
|
+
the definition holds no URL and no credential, and an Agent's word can reach only the arguments, through the input.
|
|
513
|
+
|
|
514
|
+
An Agent can also hold the tools of a server as [MCP tools](../reference/glossary.md#mcp-tools), and call them in its
|
|
515
|
+
Turn with no approval (see [Agents and Turns](agents-and-turns.md#the-mcp-tools)). Use an `mcp` Effect when the call
|
|
516
|
+
needs the approval of a person, or when the Machine makes the call with no model. The Agent picks, a Gate waits for the
|
|
517
|
+
approval, and the Effect calls the tool. The output of the Effect is the answer to the pick. Thus the approval is in the
|
|
518
|
+
record of the run, and the Machine routes on it. The default timeout is the `timeout` of the server: 60 seconds when it
|
|
519
|
+
sets none. [Call an MCP tool from a Machine](../guides/call-an-mcp-tool-from-a-machine.md) has an example.
|
|
520
|
+
|
|
505
521
|
## Where an Effect runs
|
|
506
522
|
|
|
507
523
|
You do not choose where an Effect runs. The kind, and what the Effect names, decide it. Each
|
|
@@ -518,6 +534,7 @@ commands in it:
|
|
|
518
534
|
| A `push` | The Sandbox Effector |
|
|
519
535
|
| A `dispatch` with no `target` | The Orchestrator, in its own process |
|
|
520
536
|
| A `dispatch` with a `target` | The Instance Effector |
|
|
537
|
+
| An `mcp` Effect | The Instance Effector |
|
|
521
538
|
|
|
522
539
|
A `command` that names no Effect secret runs beside the Agent's [Working tools](../reference/glossary.md#working-tools).
|
|
523
540
|
It runs as the Agent's user, with the tools of the [Sandbox Image](../reference/glossary.md#sandbox-image). The Harness
|
|
@@ -537,17 +554,19 @@ Effector is, and [Secrets and trust](secrets-and-trust.md) tells how an Effector
|
|
|
537
554
|
|
|
538
555
|
An Effect gives each outcome to `onDone`, a failure too. Route on the `outcome` field:
|
|
539
556
|
|
|
540
|
-
| Kind | The outcomes
|
|
541
|
-
| ---------- |
|
|
542
|
-
| `worktree` | `ready`, `refused`, `unknown`
|
|
543
|
-
| `command` | `exited`, `timeout`, `killed`, `unknown`
|
|
544
|
-
| `http` | `response`, `unreachable`, `refused`, `unknown`
|
|
545
|
-
| `push` | `pushed`, `rejected`, `diverged`, `unknown`
|
|
546
|
-
| `dispatch` | `started`, `settled`, `refused`, `unreachable`, `unknown`
|
|
557
|
+
| Kind | The outcomes | The output type |
|
|
558
|
+
| ---------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
559
|
+
| `worktree` | `ready`, `refused`, `unknown` | [`WorktreeOutput`](../reference/authoring-surface/type-worktreeoutput.md) |
|
|
560
|
+
| `command` | `exited`, `timeout`, `killed`, `unknown` | [`CommandOutput`](../reference/authoring-surface/type-commandoutput.md) |
|
|
561
|
+
| `http` | `response`, `unreachable`, `refused`, `unknown` | [`HttpOutput`](../reference/authoring-surface/type-httpoutput.md) |
|
|
562
|
+
| `push` | `pushed`, `rejected`, `diverged`, `unknown` | [`PushOutput`](../reference/authoring-surface/type-pushoutput.md) |
|
|
563
|
+
| `dispatch` | `started`, `settled`, `refused`, `unreachable`, `unknown` | [`DispatchOutput`](../reference/authoring-surface/type-dispatchoutput.md) |
|
|
564
|
+
| `mcp` | `returned`, `refused`, `unreachable`, `input-required`, `unknown` | [`McpCallOutput`](../reference/authoring-surface/type-mcpcalloutput.md) |
|
|
547
565
|
|
|
548
566
|
A test that fails is `exited` with a code that is not 0. A program that the container does not have is `exited` with
|
|
549
567
|
code 127. An HTTP 4xx or 5xx status is a `response`. A Workflow that refuses the run input of a `dispatch` is `refused`,
|
|
550
|
-
with the status code and the report of the refusal. `
|
|
568
|
+
with the status code and the report of the refusal. A tool of an `mcp` Effect that ran and failed is `returned` with
|
|
569
|
+
`isError: true`. `unknown` means that jr2 cannot tell what the Effect did.
|
|
551
570
|
|
|
552
571
|
Each union is open: it holds a stand-in member, `LaterOutcome`, so a later release can add an outcome and your Machine
|
|
553
572
|
still works. Route on what you know, and give the rest a last arm with no guard. With no match, the run stays in that
|
|
@@ -576,6 +595,7 @@ jr2 records its output. After an Orchestrator restart, jr2 reads the record:
|
|
|
576
595
|
| A `worktree()` | jr2 attaches to it again. When the Harness does not know it, jr2 sends it again: a cut is idempotent. |
|
|
577
596
|
| A `push` | jr2 follows it. When the Sandbox Effector lost it, jr2 pushes the same commit again, and no other commit. With no commit recorded, the outcome is `unknown`. |
|
|
578
597
|
| An `http` Effect | jr2 follows it. When no Effector holds it, jr2 sends it again only if it is `idempotent`. Else the outcome is `unknown`. |
|
|
598
|
+
| An `mcp` Effect | As an `http` Effect. jr2 does not read the `idempotentHint` of a tool: only your `idempotent` mark counts. |
|
|
579
599
|
| A `dispatch` | jr2 sends the start again, with the same key. The Orchestrator answers with the run that the key started, and it starts no second run. |
|
|
580
600
|
|
|
581
601
|
A `command` that names no Effect secret runs the code of the Worktree, and that code can spend a Stand-in. Thus jr2 does
|
|
@@ -583,7 +603,8 @@ not run it two times. A `push`, and a `command` that names an Effect secret, run
|
|
|
583
603
|
jr2 can send them again with that commit.
|
|
584
604
|
|
|
585
605
|
To try again, write it in the Machine: a route from the outcome back into the state. Mark an `http` Effect `idempotent`
|
|
586
|
-
only when a second call is safe: the call has its own idempotency key, or it only reads.
|
|
606
|
+
only when a second call is safe: the call has its own idempotency key, or it only reads. The same rule is true for an
|
|
607
|
+
`mcp` Effect.
|
|
587
608
|
|
|
588
609
|
## When the state exits
|
|
589
610
|
|
|
@@ -592,8 +613,8 @@ When the run leaves the state, the Effect stops:
|
|
|
592
613
|
- jr2 kills the process group of a `command` that names no Effect secret.
|
|
593
614
|
- The Sandbox Effector stops a `command` that names an Effect secret. It sends `SIGTERM`, waits 5 seconds, then sends
|
|
594
615
|
`SIGKILL`.
|
|
595
|
-
- An `http` Effect and a `push` have no stop. jr2 stops waiting for the output, but the Effector can
|
|
596
|
-
work.
|
|
616
|
+
- An `http` Effect, an `mcp` Effect and a `push` have no stop. jr2 stops waiting for the output, but the Effector can
|
|
617
|
+
still finish the work.
|
|
597
618
|
- A `dispatch` with `wait` stops its wait. The run that it started continues.
|
|
598
619
|
|
|
599
620
|
jr2 records the stop, and the Machine gets no output. There is no "finally" in a Machine: cleanup is a state. Put an
|
|
@@ -633,11 +654,14 @@ pick waits for its answer.
|
|
|
633
654
|
a `committer` field there.
|
|
634
655
|
- Each param of a pick that enters an Effect's state has a reader: the Effect's input, `fill`, a guard or an `assign`.
|
|
635
656
|
`createMachine` refuses a param that nothing reads, and a `fill` key that is also a param.
|
|
636
|
-
- A packaged Machine can leave an `http` URL, a `command` argv, one Effect secret name
|
|
637
|
-
Open. The composer binds it one time with `customize()`. `jr2 up` refuses
|
|
657
|
+
- A packaged Machine can leave an `http` URL, a `command` argv, one Effect secret name, the `target` of a `dispatch`, or
|
|
658
|
+
the server and the tool of an `mcp` Effect Open. The composer binds it one time with `customize()`. `jr2 up` refuses
|
|
659
|
+
an Open part that nobody bound.
|
|
638
660
|
- A `dispatch` with no `target` names a Workflow that the Assembly has. `jr2 up` refuses a name that it does not have,
|
|
639
661
|
and an `input` schema that the input of that Workflow does not take.
|
|
640
662
|
- The `url` of a `dispatch` target is an origin only: a scheme, a host and a port, with no path, no query and no user.
|
|
663
|
+
- An `mcp` Effect names a remote server that the `mcp` block declares. `jr2 up` refuses a server that the block does not
|
|
664
|
+
declare, and a stdio server.
|
|
641
665
|
|
|
642
666
|
The guides give the refusal text of each rule.
|
|
643
667
|
|
|
@@ -646,13 +670,17 @@ The guides give the refusal text of each rule.
|
|
|
646
670
|
- [Run a command or call a URL with an Effect](../guides/run-a-command-or-call-a-url.md)
|
|
647
671
|
- [Push and sign a branch](../guides/push-and-sign-a-branch.md)
|
|
648
672
|
- [Start a run from a run](../guides/start-a-run-from-a-run.md)
|
|
673
|
+
- [Call an MCP tool from a Machine](../guides/call-an-mcp-tool-from-a-machine.md)
|
|
649
674
|
- [Workspaces](workspaces.md), [The Menu](the-menu.md), [Secrets and trust](secrets-and-trust.md)
|
|
650
675
|
- Reference: [`command`](../reference/authoring-surface/command.md), [`http`](../reference/authoring-surface/http.md),
|
|
651
676
|
[`push`](../reference/authoring-surface/push.md), [`dispatch`](../reference/authoring-surface/dispatch.md),
|
|
652
|
-
[`
|
|
677
|
+
[`mcp`](../reference/authoring-surface/mcp.md), [`fromPick`](../reference/authoring-surface/frompick.md),
|
|
678
|
+
[`answer`](../reference/authoring-surface/answer.md)
|
|
653
679
|
- [ADR-0067](../reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md):
|
|
654
680
|
an Effect is an actor slot, and runs at most once unless marked idempotent
|
|
655
681
|
- [ADR-0068](../reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md): an Effector holds
|
|
656
682
|
an Effect's secrets and signs its wire
|
|
657
683
|
- [ADR-0071](../reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md): a run starts a run through a
|
|
658
684
|
`dispatch` Effect
|
|
685
|
+
- [ADR-0079](../reference/decisions/0079-an-agent-holds-mcp-tools-a-machine-calls-them-as-an-effect-and-the-machine-is-the-approval.md):
|
|
686
|
+
a Machine calls an MCP server as an Effect, and the Machine is the approval
|