@awebai/oats 0.29.4 → 0.30.1
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/README.md +12 -6
- package/bin/oats.mjs +194 -50
- package/docs/capabilities.md +160 -171
- package/docs/capability-manifest.schema.json +6 -11
- package/docs/configuration.md +213 -64
- package/docs/design/2026-09-16-knowledge-capability-contract.md +36 -50
- package/docs/design/2026-09-23-workspace-module-contracts.md +377 -544
- package/docs/design/2026-09-26-okf-knowledge-operations.md +132 -357
- package/docs/design/2026-09-27-team-model-v2.md +97 -117
- package/docs/design/2026-09-28-automations-trust.md +38 -0
- package/docs/design/2026-09-28-soul-launch-preference.md +63 -0
- package/docs/design/HISTORY.md +65 -0
- package/docs/design/README.md +23 -54
- package/docs/desktop-cli-api.md +1787 -1777
- package/docs/desktop.md +30 -91
- package/docs/execution-targets.md +146 -292
- package/docs/first-team.md +31 -17
- package/docs/implementation.md +77 -288
- package/docs/integrations.md +118 -320
- package/docs/knowledge-capability-authoring.md +25 -52
- package/docs/knowledge-reference/acceptance.md +3 -3
- package/docs/knowledge-reference/adoption.md +1 -1
- package/docs/knowledge-reference/harvester.md +2 -2
- package/docs/knowledge-reference/package-craft.md +3 -3
- package/docs/knowledge-reference/provider-mapping.md +3 -6
- package/docs/knowledge-reference/reader-capture.md +3 -3
- package/docs/knowledge-theory.md +62 -166
- package/docs/knowledge.md +225 -404
- package/docs/layers.md +42 -97
- package/docs/oats-local.schema.json +58 -5
- package/docs/oats-membership.schema.json +1 -8
- package/docs/oats-package.schema.json +5 -5
- package/docs/oats-workspace.schema.json +8 -22
- package/docs/official-catalog.md +25 -28
- package/docs/packages.md +45 -63
- package/docs/plans/0.30-close-out.md +83 -0
- package/docs/release-lane.md +82 -0
- package/docs/release-notes/oats-framework-v1.1.3.md +10 -8
- package/docs/release-notes/v0.19.0.md +48 -147
- package/docs/release-notes/v0.19.1.md +2 -3
- package/docs/release-notes/v0.19.3.md +2 -15
- package/docs/release-notes/v0.20.0.md +0 -15
- package/docs/release-notes/v0.22.0.md +71 -138
- package/docs/release-notes/v0.22.1.md +42 -90
- package/docs/release-notes/v0.22.10.md +1 -1
- package/docs/release-notes/v0.22.11.md +1 -47
- package/docs/release-notes/v0.22.12.md +4 -13
- package/docs/release-notes/v0.22.13.md +1 -42
- package/docs/release-notes/v0.22.14.md +3 -11
- package/docs/release-notes/v0.22.15.md +1 -46
- package/docs/release-notes/v0.22.16.md +6 -8
- package/docs/release-notes/v0.22.18.md +1 -99
- package/docs/release-notes/v0.22.19.md +3 -14
- package/docs/release-notes/v0.22.2.md +6 -15
- package/docs/release-notes/v0.22.3.md +0 -1
- package/docs/release-notes/v0.22.4.md +1 -14
- package/docs/release-notes/v0.22.5.md +2 -12
- package/docs/release-notes/v0.22.6.md +0 -3
- package/docs/release-notes/v0.23.0.md +9 -25
- package/docs/release-notes/v0.23.1.md +9 -25
- package/docs/release-notes/v0.23.2.md +2 -4
- package/docs/release-notes/v0.24.0.md +56 -97
- package/docs/release-notes/v0.24.1.md +7 -11
- package/docs/release-notes/v0.24.10.md +34 -45
- package/docs/release-notes/v0.24.11.md +12 -20
- package/docs/release-notes/v0.24.12.md +35 -48
- package/docs/release-notes/v0.24.13.md +34 -41
- package/docs/release-notes/v0.24.2.md +9 -13
- package/docs/release-notes/v0.24.3.md +7 -11
- package/docs/release-notes/v0.24.4.md +6 -6
- package/docs/release-notes/v0.24.5.md +6 -10
- package/docs/release-notes/v0.24.6.md +2 -5
- package/docs/release-notes/v0.24.7.md +46 -75
- package/docs/release-notes/v0.24.8.md +58 -96
- package/docs/release-notes/v0.24.9.md +38 -54
- package/docs/release-notes/v0.25.0.md +59 -76
- package/docs/release-notes/v0.25.1.md +57 -81
- package/docs/release-notes/v0.25.2.md +51 -70
- package/docs/release-notes/v0.25.3.md +11 -13
- package/docs/release-notes/v0.25.4.md +9 -13
- package/docs/release-notes/v0.25.5.md +3 -5
- package/docs/release-notes/v0.25.6.md +20 -29
- package/docs/release-notes/v0.25.7.md +5 -7
- package/docs/release-notes/v0.25.8.md +26 -39
- package/docs/release-notes/v0.26.0.md +175 -646
- package/docs/release-notes/v0.27.0.md +4 -5
- package/docs/release-notes/v0.27.1.md +4 -6
- package/docs/release-notes/v0.27.2.md +1 -1
- package/docs/release-notes/v0.28.0.md +57 -124
- package/docs/release-notes/v0.29.0.md +89 -208
- package/docs/release-notes/v0.29.1.md +1 -1
- package/docs/release-notes/v0.29.2.md +3 -4
- package/docs/release-notes/v0.30.0.md +205 -0
- package/docs/release-notes/v0.30.1.md +123 -0
- package/docs/schedules.md +280 -363
- package/docs/servers.md +99 -117
- package/docs/soul.schema.json +2 -9
- package/docs/souls-and-instances.md +145 -158
- package/docs/workspaces.md +137 -215
- package/lib/automations.mjs +21 -6
- package/lib/core.mjs +226 -74
- package/lib/instance-events.mjs +1 -1
- package/lib/instance-inspect.mjs +109 -34
- package/lib/instance-lifecycle.mjs +14 -1
- package/lib/instance-resolution.mjs +26 -27
- package/lib/launch-preference.mjs +87 -0
- package/lib/materialize.mjs +3 -3
- package/lib/packages.mjs +1 -1
- package/lib/resolve.mjs +30 -88
- package/lib/schedule.mjs +1 -1
- package/lib/teams-verbs.mjs +195 -0
- package/lib/teams.mjs +190 -0
- package/lib/triggers.mjs +2 -2
- package/lib/workspace.mjs +54 -147
- package/package-catalog.json +10 -16
- package/package.json +1 -3
- package/skills/oats-getting-started/SKILL.md +25 -13
- package/capabilities/oats-authoring/LICENSE +0 -21
- package/capabilities/oats-authoring/oats-package.json +0 -11
- package/capabilities/oats-authoring/oats.json +0 -12
- package/capabilities/oats-authoring/skills/integration-authoring/SKILL.md +0 -84
- package/capabilities/oats-authoring/skills/skill-craft/SKILL.md +0 -109
- package/capabilities/oats-authoring/skills/soul-craft/SKILL.md +0 -116
- package/capabilities/oats-aweb/bin/oats-aweb-binding.mjs +0 -11
- package/capabilities/oats-aweb/bin/oats-aweb.mjs +0 -1338
- package/capabilities/oats-aweb/injects/aweb.md +0 -47
- package/capabilities/oats-aweb/lib/binding-wire.mjs +0 -356
- package/capabilities/oats-aweb/lib/captured-execution.mjs +0 -91
- package/capabilities/oats-aweb/lib/captured-native.mjs +0 -91
- package/capabilities/oats-aweb/lib/grant-custody.mjs +0 -38
- package/capabilities/oats-aweb/lib/invocation-shape.mjs +0 -135
- package/capabilities/oats-aweb/lib/portable-binding.mjs +0 -146
- package/capabilities/oats-aweb/lib/session-readiness.mjs +0 -56
- package/capabilities/oats-aweb/lib/wake-receive.mjs +0 -56
- package/capabilities/oats-aweb/oats.json +0 -208
- package/capabilities/oats-aweb/skills/LICENSE +0 -21
- package/capabilities/oats-aweb/skills/VENDORED.md +0 -31
- package/capabilities/oats-aweb/skills/aweb-identity/SKILL.md +0 -201
- package/capabilities/oats-aweb/skills/aweb-messaging/SKILL.md +0 -161
- package/capabilities/oats-aweb/skills/aweb-messaging/references/messaging-scenarios.md +0 -61
- package/capabilities/oats-aweb/skills/aweb-team-membership/SKILL.md +0 -116
- package/capabilities/oats-aweb/skills/aweb-team-membership/references/team-membership-reference.md +0 -74
- package/capabilities/oats-aweb/skills/oats-aweb/SKILL.md +0 -216
- package/capabilities/oats-jira/bin/oats-jira.mjs +0 -40
- package/capabilities/oats-jira/injects/jira.md +0 -10
- package/capabilities/oats-jira/oats.json +0 -22
- package/capabilities/oats-jira/skills/jira-tasks/SKILL.md +0 -179
- package/capabilities/oats-linear/bin/oats-linear-hook.mjs +0 -34
- package/capabilities/oats-linear/bin/oats-linear.mjs +0 -344
- package/capabilities/oats-linear/injects/linear.md +0 -8
- package/capabilities/oats-linear/oats.json +0 -24
- package/capabilities/oats-linear/skills/linear-tasks/SKILL.md +0 -223
- package/capabilities/oats-okf/bin/oats-okf-binding.mjs +0 -14
- package/capabilities/oats-okf/bin/oats-okf.mjs +0 -209
- package/capabilities/oats-okf/injects/okf.md +0 -42
- package/capabilities/oats-okf/lib/binding-wire.mjs +0 -348
- package/capabilities/oats-okf/lib/captured-worker.mjs +0 -109
- package/capabilities/oats-okf/lib/config.mjs +0 -124
- package/capabilities/oats-okf/lib/consult.mjs +0 -518
- package/capabilities/oats-okf/lib/harvest-status.mjs +0 -88
- package/capabilities/oats-okf/lib/harvest-switch.mjs +0 -94
- package/capabilities/oats-okf/lib/inspection.mjs +0 -119
- package/capabilities/oats-okf/lib/invocation-context.mjs +0 -111
- package/capabilities/oats-okf/lib/invocation-shape.mjs +0 -135
- package/capabilities/oats-okf/lib/io.mjs +0 -118
- package/capabilities/oats-okf/lib/migration.mjs +0 -137
- package/capabilities/oats-okf/lib/okf-validate.mjs +0 -123
- package/capabilities/oats-okf/lib/portable-binding.mjs +0 -199
- package/capabilities/oats-okf/lib/source-contract.mjs +0 -46
- package/capabilities/oats-okf/lib/sources.mjs +0 -424
- package/capabilities/oats-okf/lib/stores.mjs +0 -473
- package/capabilities/oats-okf/lib/worker.mjs +0 -497
- package/capabilities/oats-okf/oats.json +0 -148
- package/capabilities/oats-okf/schemas/okf-base.schema.json +0 -46
- package/capabilities/oats-okf/schemas/okf-bindings.schema.json +0 -112
- package/capabilities/oats-okf/schemas/okf-portable-declaration.schema.json +0 -87
- package/capabilities/oats-okf/schemas/okf-portable-payload.schema.json +0 -113
- package/capabilities/oats-okf/schemas/okf-soul.schema.json +0 -37
- package/capabilities/oats-okf/skills/okf-consultation/SKILL.md +0 -144
- package/capabilities/oats-okf/skills/okf-consultation/references/consult.md +0 -86
- package/capabilities/oats-okf/skills/okf-instance-knowledge/SKILL.md +0 -104
- package/capabilities/oats-okf-harvest/bin/okf-harvest.mjs +0 -140
- package/capabilities/oats-okf-harvest/injects/harvester.md +0 -12
- package/capabilities/oats-okf-harvest/oats.json +0 -26
- package/capabilities/oats-okf-harvest/skills/knowledge-harvest/SKILL.md +0 -168
- package/capabilities/oats-okf-harvest/skills/knowledge-theory/SKILL.md +0 -192
- package/capabilities/oats-okf-harvest/skills/okf-authoring/SKILL.md +0 -151
- package/capabilities/oats-okf-harvest/skills/okf-authoring/scripts/okf-validate.mjs +0 -123
- package/capabilities/oats-okf-maintenance/bin/okf-maintenance.mjs +0 -170
- package/capabilities/oats-okf-maintenance/injects/maintainer.md +0 -12
- package/capabilities/oats-okf-maintenance/lib/provenance.mjs +0 -50
- package/capabilities/oats-okf-maintenance/oats.json +0 -21
- package/capabilities/oats-okf-maintenance/skills/knowledge-review/SKILL.md +0 -159
- package/capabilities/oats-okf-maintenance/skills/knowledge-theory/SKILL.md +0 -192
- package/capabilities/oats-okf-maintenance/skills/okf-authoring/SKILL.md +0 -151
- package/capabilities/oats-okf-maintenance/skills/okf-authoring/scripts/okf-validate.mjs +0 -123
- package/capabilities/oats-okf-maintenance/skills/okf-trigger-setup/SKILL.md +0 -146
- package/capabilities/oats-review/injects/review.md +0 -69
- package/capabilities/oats-review/oats.json +0 -10
- package/capabilities/oats-review/skills/code-review/SKILL.md +0 -44
- package/capabilities/oats-review/skills/security-review/SKILL.md +0 -59
- package/docs/conventions.md +0 -90
- package/docs/design/2026-09-07-architecture-reassessment.md +0 -131
- package/docs/design/2026-09-07-desktop-souls-capabilities.md +0 -50
- package/docs/design/2026-09-07-mobile-agent-management-proposal.md +0 -228
- package/docs/design/2026-09-08-expert-assisted-deployment-proposal.md +0 -558
- package/docs/design/2026-09-13-knowledge-and-memory-direction.md +0 -744
- package/docs/design/2026-09-13-knowledge-implementation.md +0 -127
- package/docs/design/2026-09-13-knowledge-location-contract.md +0 -340
- package/docs/design/2026-09-14-artifact-retention-contract.md +0 -190
- package/docs/design/2026-09-14-portable-souls-and-git-workspaces.md +0 -708
- package/docs/design/2026-09-14-portable-souls-contract-amendments.md +0 -85
- package/docs/design/2026-09-14-portable-souls-explainer.md +0 -750
- package/docs/design/2026-09-15-captured-dispatch.md +0 -127
- package/docs/design/2026-09-15-captured-resolution-records.md +0 -143
- package/docs/design/2026-09-15-package-preparation.md +0 -100
- package/docs/design/2026-09-15-portable-data-contract.md +0 -121
- package/docs/design/2026-09-15-portable-declarations.md +0 -189
- package/docs/design/2026-09-15-portable-souls-handoff.md +0 -150
- package/docs/design/2026-09-15-portable-souls-implementation.md +0 -417
- package/docs/design/2026-09-15-selection-lock-and-approval.md +0 -122
- package/docs/design/2026-09-15-source-observation.md +0 -119
- package/docs/design/2026-09-16-captured-admission.md +0 -77
- package/docs/design/2026-09-16-captured-helper-dispatch.md +0 -105
- package/docs/design/2026-09-16-captured-launch-inputs.md +0 -42
- package/docs/design/2026-09-16-command-profile-preparation.md +0 -86
- package/docs/design/2026-09-16-fresh-install-first-rollout.md +0 -47
- package/docs/design/2026-09-16-fresh-operator-walkthrough.md +0 -282
- package/docs/design/2026-09-16-messaging-capability-contract.md +0 -59
- package/docs/design/2026-09-16-portable-migration-evidence.md +0 -158
- package/docs/design/2026-09-16-portable-onboarding.md +0 -179
- package/docs/design/2026-09-16-prepare-request-transport.md +0 -26
- package/docs/design/2026-09-16-provider-binding-codecs.md +0 -98
- package/docs/design/2026-09-16-provider-binding-wire.md +0 -274
- package/docs/design/2026-09-17-capability-helper-input-contract.md +0 -95
- package/docs/design/2026-09-17-captured-backend-parity.md +0 -53
- package/docs/design/2026-09-17-captured-native-start.md +0 -58
- package/docs/design/2026-09-17-portable-boundary-hookup.md +0 -19
- package/docs/design/2026-09-17-portable-boundary-resources.md +0 -52
- package/docs/design/2026-09-17-public-captured-start.md +0 -108
- package/docs/design/2026-09-17-public-prepare-request.md +0 -90
- package/docs/design/2026-09-18-captured-pi-host.md +0 -205
- package/docs/design/2026-09-18-first-cut-release-checklist.md +0 -131
- package/docs/design/2026-09-18-herdr-protocol-compatibility.md +0 -60
- package/docs/design/2026-09-20-redesign-program-board.md +0 -142
- package/docs/design/2026-09-20-workspace-and-portable-adoption-plan.md +0 -289
- package/docs/design/2026-09-20-workspace-onboarding-public.md +0 -207
- package/docs/design/2026-09-22-desktop-parity-seams.md +0 -58
- package/docs/design/2026-09-23-simplified-workspace-model.md +0 -711
- package/docs/design/2026-09-23-workspace-v2-implementation-plan.md +0 -65
- package/docs/design/2026-09-24-desktop-phase-f-boundary.md +0 -242
- package/docs/design/2026-09-24-phase-d-plan.md +0 -305
- package/docs/design/2026-09-25-teams-contract.md +0 -258
- package/docs/design/2026-09-26-desktop-design-brief-architecture.md +0 -241
- package/docs/design/desktop-ux-plan.md +0 -362
- package/docs/design/launch-configurations.md +0 -168
- package/docs/design/okf-mirror-provenance.md +0 -105
- package/docs/design/operations-contract.md +0 -141
- package/docs/oats-member.schema.json +0 -38
- package/skills/integration-authoring/SKILL.md +0 -84
- package/skills/oats-support/SKILL.md +0 -79
- package/skills/skill-craft/SKILL.md +0 -109
- package/skills/soul-craft/SKILL.md +0 -116
package/docs/schedules.md
CHANGED
|
@@ -1,120 +1,102 @@
|
|
|
1
1
|
# Schedules
|
|
2
2
|
|
|
3
3
|
A schedule launches an agent, runs an oats command, or wakes an existing
|
|
4
|
-
instance on a cron.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
instance on a cron. A [trigger](#triggers) spawns an agent when a GitHub pull
|
|
5
|
+
request event matches. Both are defined at one of two levels:
|
|
6
|
+
|
|
7
|
+
- **In the workspace**: a YAML file committed in a member repository, shared
|
|
8
|
+
through Git, addressed `<member>/<id>`, and run only on the host its
|
|
9
|
+
`runsOn` names. See [Workspace triggers and schedules](#workspace-triggers-and-schedules).
|
|
10
|
+
- **Locally**: in `<deployment>/oats-schedules.json`, addressed `local/<id>`
|
|
11
|
+
(or the bare `<id>`). This file belongs to one machine, like the
|
|
12
|
+
`oats-local.yaml` beside it: its definitions name absolute paths on that
|
|
13
|
+
machine, and only that machine runs them.
|
|
14
|
+
|
|
15
|
+
The deployment is the directory holding `oats-local.yaml`, found walking up
|
|
16
|
+
from the current directory or `--dir` ([configuration.md](configuration.md#the-deployment-directory));
|
|
17
|
+
with none in reach, the commands answer `E_LOCAL_MISSING`. Every command run
|
|
18
|
+
inside the deployment, including from an instance home, sees the same
|
|
19
|
+
definitions.
|
|
20
|
+
|
|
21
|
+
There is no daemon. One host timer (a launchd user agent on macOS, a systemd
|
|
22
|
+
user timer on Linux) runs `oats schedule tick --host` once a minute. The tick
|
|
23
|
+
evaluates only the current minute, launches what is due through the same
|
|
24
|
+
`spawn`, `session start` and `session input` paths you use by hand, polls the
|
|
25
|
+
triggers that are due, records what it observed, and exits. Minutes missed
|
|
26
|
+
while the machine slept are skipped, never replayed; there are no retries and
|
|
27
|
+
no queue. A schedule on a registered server keeps running while your laptop
|
|
28
|
+
sleeps.
|
|
29
|
+
|
|
30
|
+
The design is in the
|
|
31
|
+
[knowledge-operations design record](design/2026-09-26-okf-knowledge-operations.md#23-triggers)
|
|
32
|
+
(§2.3 and §2.3a).
|
|
20
33
|
|
|
21
34
|
## Files
|
|
22
35
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
scopes). The two caps are separate: a running scheduled job never holds a
|
|
34
|
-
trigger, and a trigger's instances never hold a schedule. One host
|
|
35
|
-
lock serializes ticks, run-now, reconcile and remove; it is never reclaimed
|
|
36
|
-
by another process: a lock whose owner is unreadable or gone is reported
|
|
37
|
-
with the directory to remove, and the holder removes its own lock on exit
|
|
38
|
-
and on SIGINT/SIGTERM. Definition edits take a short per-scope lock.
|
|
39
|
-
|
|
40
|
-
Captured (versioned) definitions are refused (the captured/portable path was removed in 0.26):
|
|
41
|
-
see [Captured definitions](#captured-definitions-removed-in-026).
|
|
36
|
+
| File | Holds |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `<deployment>/oats-schedules.json` | This machine's local definitions, `{version: 1, jobs: {<id>: …}}`, local triggers included (`kind: "trigger"`). |
|
|
39
|
+
| `<deployment>/.agents/automations/snapshot.json` | The workspace definitions discovered from the members. |
|
|
40
|
+
| `<deployment>/.agents/schedules/` | Run state: `state.json` (last minute and recent runs per job), `triggers.json` (polls, pending events, fired keys) and one lock directory per running job. |
|
|
41
|
+
| `~/.oats/schedules/registry.json` | The deployments this host ticks, `maxConcurrent` (default 1: running scheduled jobs) and `triggersMaxConcurrent` (absent: no host cap on trigger-spawned live instances). The two caps are separate. |
|
|
42
|
+
|
|
43
|
+
One host lock serializes ticks, run-now, reconcile and remove. It is never
|
|
44
|
+
reclaimed by another process: a lock whose owner is gone is reported with the
|
|
45
|
+
directory to remove.
|
|
42
46
|
|
|
43
47
|
## Kinds
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
is refused when
|
|
59
|
-
minute and ending with `oats retire
|
|
60
|
-
(`{cron, tz, message}`) attaches a wake schedule to each
|
|
61
|
-
|
|
62
|
-
- **command** `{
|
|
63
|
-
|
|
64
|
-
inside the
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
`--artifact-set`) is refused when saved (`E_SCHEDULE_INVALID`, field `argv`).
|
|
71
|
-
- **wake** `{id, enabled, cron, tz, kind: "wake", home, message}` — every
|
|
72
|
-
due minute inspects the instance at `home` through its session receipts.
|
|
73
|
-
Running: `message` is delivered once with `session input`. Not running
|
|
74
|
-
(absent, dead pane or fallback shell): the same home is started with
|
|
49
|
+
Every definition carries `id`, `enabled`, `cron`, `tz` and `kind`. `cron` has
|
|
50
|
+
five fields (minute hour day month weekday) and `tz` is a required IANA zone;
|
|
51
|
+
both are evaluated by the croner library.
|
|
52
|
+
|
|
53
|
+
- **spawn** `{…, agent, agentsRoot?, repo?, backend?, purpose?, task,
|
|
54
|
+
launchConfig?, harness?, model?, yolo?, wake?}` — every due minute launches
|
|
55
|
+
one disposable instance of `agent` with the options `oats spawn` takes.
|
|
56
|
+
`agentsRoot`, when given, must be the deployment's `agents/` root; `repo`
|
|
57
|
+
is the work repository, as `--repo`. `model` is a model id (a letter or
|
|
58
|
+
digit, then letters, digits and `. _ : / @ + - [ ]`, at most 128
|
|
59
|
+
characters) or `@native-default`; `agent` and `repo` never start with `-`,
|
|
60
|
+
so no value can be read as an option of the child `oats spawn`. Each run is
|
|
61
|
+
named `<agent>-<purpose or id>-<YYYYMMDDHHMM>`, at most 64 characters (a
|
|
62
|
+
longer one is refused when saved, `E_SCHEDULE_INVALID`). The task gets a
|
|
63
|
+
trailing block naming the job and the minute and ending with `oats retire
|
|
64
|
+
--self`. `wake` (`{cron, tz, message}`) attaches a wake schedule to each
|
|
65
|
+
launched instance.
|
|
66
|
+
- **command** `{…, cwd, argv}` — runs an oats-only argv (`argv[0]` is `oats`,
|
|
67
|
+
no shell; `oats schedule` itself is refused) in `cwd`, an existing directory
|
|
68
|
+
inside the deployment. The runner tracks any instance the command's
|
|
69
|
+
envelope names, including an independent worker it reports, until its home
|
|
70
|
+
is gone. A command's return is not task completion.
|
|
71
|
+
- **wake** `{…, home, message}` — every due minute inspects the instance at
|
|
72
|
+
`home`. Running: `message` is delivered once as terminal input (bracketed
|
|
73
|
+
paste plus Enter), never an interrupt. Not running: the home is started with
|
|
75
74
|
`session start` and the message becomes the job's one pending delivery,
|
|
76
|
-
completed on a later tick
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
- **operation** `{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
launch receipt the provider answers (a harvester it spawned) is followed
|
|
88
|
-
until that home is gone; the source home is never treated as a launch.
|
|
89
|
-
Unobservable or still starting: skipped with the reason, delivery kept
|
|
90
|
-
pending. Whether a running harness is busy cannot be seen from the
|
|
91
|
-
terminal: delivery is terminal input (bracketed paste plus Enter), never an
|
|
92
|
-
interrupt, never Ctrl-C, never into a stopped or starting shell. Word wake
|
|
93
|
-
messages so that receiving one again is harmless.
|
|
94
|
-
|
|
95
|
-
`cron` has five fields (minute hour day month weekday) and `tz` is a
|
|
96
|
-
required IANA zone; both are evaluated by the croner library. `--wake-every
|
|
97
|
-
N` at spawn time means `*/N * * * *`: every 7 fires at :00, :07, ... :56 and
|
|
98
|
-
then :00 again, so 1, 5, 10, 15 and 30 give an even cadence.
|
|
75
|
+
completed on a later tick once the session is active; the home is started
|
|
76
|
+
again only at due minutes, so a harness that keeps exiting is not restarted
|
|
77
|
+
in a loop. Unobservable or still starting: skipped, delivery kept pending.
|
|
78
|
+
Word wake messages so that receiving one again is harmless.
|
|
79
|
+
- **operation** `{…, operation, home}` — runs a provider operation such as
|
|
80
|
+
`knowledge:harvest` in the instance at `home` through `oats operation run
|
|
81
|
+
<layer>:<name> --home <home>`. The provider is whatever fills that layer
|
|
82
|
+
when the job runs. Tracking is that of a command job.
|
|
83
|
+
|
|
84
|
+
`--wake-every N` at spawn time means `*/N * * * *`: every 7 fires at :00, :07,
|
|
85
|
+
… :56 and then :00 again, so 1, 5, 10, 15 and 30 give an even cadence.
|
|
99
86
|
|
|
100
87
|
## Triggers
|
|
101
88
|
|
|
102
|
-
A **trigger**
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
tick with its own environment, which sets only `PATH` and `OATS_HOME_DIR`. `gh`
|
|
114
|
-
logged in with the keyring or its config file under your HOME works there. A
|
|
115
|
-
`GH_TOKEN` or `GITHUB_TOKEN` exported in your shell does not reach it.
|
|
116
|
-
`oats trigger test` reports where `gh`'s credential comes from (`gh.credentialSource`:
|
|
117
|
-
`keyring`, `config`, `env:<VAR>`) and warns when the timer cannot reach it.
|
|
89
|
+
A **trigger** is an event-driven spawn: "when EVENT matches, spawn a NEW
|
|
90
|
+
instance of SOUL with TASK". It is managed with `oats trigger …` (`oats
|
|
91
|
+
schedule …` neither lists nor edits one) and evaluated by the same host tick.
|
|
92
|
+
There is no webhook. It runs only on the host that holds it, with **that
|
|
93
|
+
host's own credentials**; a definition carries none.
|
|
94
|
+
|
|
95
|
+
The host timer runs the tick with its own environment (only `PATH` and
|
|
96
|
+
`OATS_HOME_DIR`): `gh` logged in with the keyring or its config file works
|
|
97
|
+
there, but a `GH_TOKEN` exported in your shell does not. `oats trigger test`
|
|
98
|
+
reports `gh.credentialSource` (`keyring`, `config`, `env:<VAR>`) and warns
|
|
99
|
+
when the timer cannot reach it.
|
|
118
100
|
|
|
119
101
|
```json
|
|
120
102
|
{ "id": "okf-harvest-review", "enabled": true, "kind": "trigger",
|
|
@@ -123,100 +105,74 @@ logged in with the keyring or its config file under your HOME works there. A
|
|
|
123
105
|
"labels": ["okf-harvest"], "base": "main", "poll": "2m" },
|
|
124
106
|
"spawn": { "soul": "oats.okf/knowledge-maintainer", "purpose": "review-pr-{number}",
|
|
125
107
|
"task": "Review knowledge-base PR {repo}#{number}. Load knowledge-review first.",
|
|
126
|
-
"
|
|
108
|
+
"harness": "claude", "model": "opus" },
|
|
127
109
|
"concurrency": { "max": 2, "perKey": 1 } }
|
|
128
110
|
```
|
|
129
111
|
|
|
130
|
-
- **Source
|
|
131
|
-
repository's open pull requests with the host's `gh` (`gh api
|
|
132
|
-
`state=open`, most recently updated first)
|
|
133
|
-
least `1m`). `labels` (all must be present)
|
|
134
|
-
`github.com/<owner>/<repo>`; another host
|
|
112
|
+
- **Source.** `github.pull_request` is the only source. The tick polls the
|
|
113
|
+
repository's open pull requests with the host's `gh` (`gh api
|
|
114
|
+
repos/<owner>/<repo>/pulls`, `state=open`, most recently updated first)
|
|
115
|
+
every `poll` (default `2m`, at least `1m`). `labels` (all must be present)
|
|
116
|
+
and `base` filter them. A repo is `github.com/<owner>/<repo>`; another host
|
|
117
|
+
is passed to `gh` as `--hostname`.
|
|
135
118
|
- **Events** are inferred poll over poll: `opened` (a PR first seen, not a
|
|
136
119
|
draft; the first poll sees every open PR), `reopened` (seen closed, open
|
|
137
120
|
again), `ready_for_review` (was a draft), `labeled` (now carries the filter
|
|
138
|
-
labels it lacked; without a filter, any new label)
|
|
121
|
+
labels it lacked; without a filter, any new label) and `synchronize` (a new
|
|
139
122
|
head commit).
|
|
140
|
-
- **Dedup
|
|
123
|
+
- **Dedup, at least once.** Each event has a key
|
|
141
124
|
`<trigger>:<repo>#<number>:<event>:<stamp>` (`created_at` for `opened`, the
|
|
142
|
-
head SHA for `synchronize`, `updated_at` otherwise)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
- **
|
|
154
|
-
`
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
and `on.repo` must be on the same GitHub host (`E_TRIGGER_INVALID`, field
|
|
162
|
-
`owner`): the owner check and the poll ask gh on that one host.
|
|
163
|
-
- **The spawn** is `oats spawn` (the same path as a scheduled spawn). `soul` is
|
|
164
|
-
bare or qualified (`<package>/<soul>`). `purpose` (default
|
|
165
|
-
`{trigger}-{number}`, must render to a slug) and `task` are templated from
|
|
166
|
-
**only** `{repo} {number} {url} {event} {headSha} {trigger}`: a pull
|
|
167
|
-
request's title and body are untrusted and never reach the task (a template
|
|
168
|
-
naming any other field is refused). `teams` becomes the messaging
|
|
169
|
-
capability's `join=` setting (as `--provider <messaging cap> join=<labels>`).
|
|
170
|
-
`launchConfig` (a launch configuration in the running host's
|
|
171
|
-
`oats-local.yaml` `launch-configs`), `harness`, `model`, `yolo`, `backend`
|
|
172
|
-
are as for schedules; a package template may expose any of them as a
|
|
173
|
-
parameter (`"path": "spawn.launchConfig"`).
|
|
125
|
+
head SHA for `synchronize`, `updated_at` otherwise), recorded as fired
|
|
126
|
+
**only after a successful spawn**. Until then the event stays pending, is
|
|
127
|
+
retried at every poll, and is dropped when its PR closes. A tick that dies
|
|
128
|
+
between the spawn and the record spawns the event again on the next poll
|
|
129
|
+
(held by `perKey` while the first instance lives), so a trigger's soul
|
|
130
|
+
should tolerate a second run on the same event.
|
|
131
|
+
- **Concurrency.** `max` (default 1) bounds the trigger's live instances and
|
|
132
|
+
`perKey` (default 1) those of one PR, counted from the homes'
|
|
133
|
+
`instance.json.trigger` records; a retired instance frees its slot. An event
|
|
134
|
+
over a bound stays pending (`held`). A newer push supersedes a pending
|
|
135
|
+
`synchronize` for an older head of the same PR.
|
|
136
|
+
- **The spawn** is `oats spawn`. `soul` is bare or qualified
|
|
137
|
+
(`<package>/<soul>`). `purpose` (default `{trigger}-{number}`) and `task`
|
|
138
|
+
are templated from **only** `{repo} {number} {url} {event} {headSha}
|
|
139
|
+
{trigger}`: a pull request's title and body are untrusted and never reach
|
|
140
|
+
the task. `teams` (optional) becomes the messaging capability's `join=`
|
|
141
|
+
setting (`E_TRIGGER_TEAMS` when the soul has no messaging capability).
|
|
142
|
+
`launchConfig`, `harness`, `model`, `yolo` and `backend` are as for
|
|
143
|
+
schedules.
|
|
174
144
|
- **The event reaches the instance** as `OATS_TRIGGER_EVENT_FILE`
|
|
175
145
|
(`<home>/.oats/trigger-event.json`: `{ trigger, source, repo, number, url,
|
|
176
146
|
event, headSha, labels, observedAt, key }`), given to the spawn hooks and the
|
|
177
|
-
harness
|
|
178
|
-
url, event, headSha, observedAt, eventFile }`. The task ends with a short
|
|
179
|
-
block naming the event file.
|
|
180
|
-
- **State** lives in `<scope>/.agents/schedules/triggers.json` (last poll, the
|
|
181
|
-
PRs seen, pending events, fired keys, the last error).
|
|
147
|
+
harness, and is recorded in `instance.json.trigger`.
|
|
182
148
|
|
|
183
149
|
```sh
|
|
184
150
|
oats trigger add --file trigger.json # or:
|
|
185
151
|
oats trigger add --from oats.okf:harvest-review --set repo=github.com/acme/knowledge [--id <id>]
|
|
186
152
|
oats trigger list | show <id> | enable <id> | disable <id> | remove <id>
|
|
187
|
-
oats trigger test <id> # dry run: gh
|
|
188
|
-
|
|
189
|
-
oats trigger status [<id>] # last poll, next due, pending, fired keys (time, instance), live vs max, last error
|
|
153
|
+
oats trigger test <id> # dry run: gh credentials, repo permissions, the soul, what WOULD fire
|
|
154
|
+
oats trigger status [<id>] # last poll, next due, pending and fired events, live vs max, last error
|
|
190
155
|
```
|
|
191
156
|
|
|
192
157
|
All take `--dir` and `--json` (`triggerApi: 1`). `remove` leaves the instances
|
|
193
|
-
it spawned running. `oats schedule list` does not list triggers
|
|
158
|
+
it spawned running. `oats schedule list` does not list triggers but counts
|
|
194
159
|
them (`triggers: { count, command: "oats trigger list" }`, and a line in text
|
|
195
160
|
mode). Errors: `E_TRIGGER_INVALID { field }`, `E_TRIGGER_EXISTS`,
|
|
196
|
-
`E_TRIGGER_UNKNOWN`, `E_BAD_ARGS`.
|
|
161
|
+
`E_TRIGGER_UNKNOWN`, `E_TRIGGER_TEAMS`, `E_BAD_ARGS`.
|
|
197
162
|
|
|
198
163
|
**Package trigger templates.** A package may declare `triggers: [{ id, file }]`
|
|
199
|
-
in `oats-package.json
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
commit, template }`.
|
|
164
|
+
in `oats-package.json`, each file `{ parameters: { <name>: { path, required?,
|
|
165
|
+
default?, description? } }, definition }`. `oats trigger add --from
|
|
166
|
+
<package>:<id>` reads it at the locked commit, and `--set <name>=<value>`
|
|
167
|
+
fills a parameter at its dotted `path` (a list value is comma-separated; a
|
|
168
|
+
missing required one is `E_BAD_ARGS { missing }`). See
|
|
169
|
+
[packages.md](packages.md#trigger-templates).
|
|
206
170
|
|
|
207
171
|
## Workspace triggers and schedules
|
|
208
172
|
|
|
209
|
-
|
|
210
|
-
two
|
|
211
|
-
|
|
212
|
-
- **in the workspace**: a file committed in a confirmed member repository, shared
|
|
213
|
-
through Git and named `<member>/<id>`. This is the default for anything a team
|
|
214
|
-
relies on.
|
|
215
|
-
- **locally**: in the deployment's `oats-schedules.json` (`oats trigger add`,
|
|
216
|
-
`oats schedule add`), machine-private and named `local/<id>`.
|
|
217
|
-
|
|
218
|
-
The two kinds stay separate at every step. Each has its own folder, its own file
|
|
219
|
-
kind, its own ids, its own commands, its own list and its own opt-out.
|
|
173
|
+
Anything a team relies on belongs in a confirmed member repository, shared
|
|
174
|
+
through Git and addressed `<member>/<id>`. The two kinds stay separate: each
|
|
175
|
+
has its own folder, file kind, ids, commands, list and opt-out.
|
|
220
176
|
|
|
221
177
|
| | trigger | schedule |
|
|
222
178
|
| --- | --- | --- |
|
|
@@ -224,11 +180,10 @@ kind, its own ids, its own commands, its own list and its own opt-out.
|
|
|
224
180
|
| file name anywhere in the member | `*.oats-trigger.yaml` | `*.oats-schedule.yaml` |
|
|
225
181
|
| `kind:` | `oats-trigger` | `oats-schedule` |
|
|
226
182
|
| body | `from:` + `set:` (a package template), or `on`, `spawn`, `concurrency` as above | `run: spawn \| command`, `cron`, `tz`, `agent`, `task`, `purpose`, `launchConfig`, `harness`, `model`, `yolo`, `backend`, `wake`, `argv`, `cwd` |
|
|
227
|
-
| commands | `oats trigger …` | `oats schedule …` |
|
|
228
183
|
| opt-out on this host | `triggers.disabled` | `schedules.disabled` |
|
|
229
184
|
|
|
230
|
-
Every `.yaml`/`.yml` under a canonical folder is a candidate, and so is a file
|
|
231
|
-
the kind's suffix anywhere in the member (`.yml` works too),
|
|
185
|
+
Every `.yaml`/`.yml` under a canonical folder is a candidate, and so is a file
|
|
186
|
+
with the kind's suffix anywhere in the member (`.yml` works too), for example
|
|
232
187
|
`services/billing/nightly.oats-schedule.yaml` beside the code it concerns.
|
|
233
188
|
`oats-package/`, `.git/` and `node_modules/` are never scanned.
|
|
234
189
|
|
|
@@ -256,216 +211,178 @@ runsOn: ana-laptop
|
|
|
256
211
|
owner: github.com/ana
|
|
257
212
|
```
|
|
258
213
|
|
|
259
|
-
- **The
|
|
260
|
-
|
|
261
|
-
`
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
214
|
+
- **The header.** Every file carries `kind` and `schemaVersion: 1`, plus
|
|
215
|
+
`runsOn` and `owner`, and optionally `id`, `description` and `enabled`. A
|
|
216
|
+
candidate of the wrong kind (a schedule in `oats-triggers/`) or without one
|
|
217
|
+
is an `E_AUTOMATION_SCHEMA` problem, never silently skipped.
|
|
218
|
+
- **The id** is `id:`, else the filename stem. The same id twice in one member
|
|
219
|
+
for one kind is `E_AUTOMATION_DUPLICATE`, naming both paths; the second file
|
|
220
|
+
is not listed. A trigger and a schedule may share an id. A member named
|
|
221
|
+
`local` is refused, because `local/<id>` names this host's own definitions.
|
|
222
|
+
- **A workspace schedule is `run: spawn` or `run: command`.** A command's
|
|
223
|
+
`cwd` is relative to the deployment and must stay inside it. `wake` and
|
|
224
|
+
`operation` target an instance home on one machine, so they stay local.
|
|
225
|
+
- **A workspace trigger's `owner` and `on.repo` must be on the same GitHub
|
|
226
|
+
host** (`E_TRIGGER_INVALID`, field `owner`).
|
|
227
|
+
|
|
228
|
+
**Who runs it.** A host runs a workspace trigger or schedule only when all
|
|
229
|
+
three hold:
|
|
271
230
|
|
|
272
231
|
1. its `runsOn` is this host's `host.name` in `oats-local.yaml`;
|
|
273
|
-
2. the host's authenticated `gh` account (`gh api user`, asked once per tick)
|
|
274
|
-
`owner
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
232
|
+
2. the host's authenticated `gh` account (`gh api user`, asked once per tick)
|
|
233
|
+
is its `owner`;
|
|
234
|
+
3. this host's `oats-local.yaml` trusts it (0.30):
|
|
235
|
+
|
|
236
|
+
```yaml
|
|
237
|
+
automations:
|
|
238
|
+
trust:
|
|
239
|
+
- agents/pr-review # <member>/<id>, as the list names it
|
|
240
|
+
# or trust: "*" # every automation the workspace places on this host
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Otherwise the item is listed with a reason: `assigned-elsewhere`,
|
|
244
|
+
`owner-mismatch` (this host is named, but its `gh` is logged in as someone
|
|
245
|
+
else or not at all), `host-unnamed`, or `untrusted` (placed here but not
|
|
246
|
+
trusted: it never runs, and `oats workspace status` warns with the exact
|
|
247
|
+
line to add). Both names come from a commit, so anyone who can commit to a
|
|
248
|
+
member could name your host; trust is the operator's own yes. A trust entry
|
|
249
|
+
that names no workspace automation is a warning (`automation-trust-stale`),
|
|
250
|
+
not an error: its member may not have synced yet. Your own `oats trigger
|
|
251
|
+
add` / `oats schedule add` definitions need no trust.
|
|
252
|
+
|
|
253
|
+
**Opting out on one host.** `oats trigger disable <member>/<id>` writes
|
|
287
254
|
`triggers.disabled`, and `oats schedule disable <member>/<id>` writes
|
|
288
|
-
`schedules.disabled`, in `oats-local.yaml
|
|
289
|
-
workspace definition is never edited or removed
|
|
290
|
-
`E_AUTOMATION_WORKSPACE`): change the file in Git.
|
|
255
|
+
`schedules.disabled`, in `oats-local.yaml`; `enable` removes the entry. A
|
|
256
|
+
workspace definition is never edited or removed from the CLI (`update` and
|
|
257
|
+
`remove` answer `E_AUTOMATION_WORKSPACE`): change the file in Git.
|
|
291
258
|
|
|
292
259
|
**Refresh.**
|
|
293
260
|
|
|
294
|
-
- `oats sync`
|
|
295
|
-
members into
|
|
296
|
-
|
|
297
|
-
- The host tick
|
|
298
|
-
when
|
|
299
|
-
the
|
|
300
|
-
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
- Run inside a checkout of that member, it writes `oats-triggers/<id>.yaml` or
|
|
310
|
-
`oats-schedules/<id>.yaml` there, for you to commit and push.
|
|
311
|
-
- Anywhere else, it prints the file.
|
|
312
|
-
- Either way, the file is read back and validated first.
|
|
313
|
-
- `oats trigger test <member>/<id>` checks the placement, and everything else it
|
|
314
|
-
checked before, on this host.
|
|
315
|
-
|
|
316
|
-
Everything above still holds: the soul must resolve here, templates name only the
|
|
317
|
-
whitelisted fields, a PR's text is never interpolated, and no definition carries a
|
|
318
|
-
credential.
|
|
319
|
-
|
|
320
|
-
## Captured definitions (removed in 0.26)
|
|
321
|
-
|
|
322
|
-
0.24–0.25 could save captured command definitions: `definitionVersion`,
|
|
323
|
-
`recurrencePolicy` (`capture` or `prepare-on-tick`), an `execution` template and a
|
|
324
|
-
`preparation` request, run against a captured deployment/resolution. That path
|
|
325
|
-
was removed in 0.26:
|
|
326
|
-
|
|
327
|
-
- `add` and `update` refuse any of those four keys (`E_SCHEDULE_INVALID`, the
|
|
328
|
-
key as `field`), locally and, with `--server`, before anything is forwarded.
|
|
329
|
-
- A stored captured definition is invalid on its own job: every tick reports it
|
|
330
|
-
(`invalid`, "captured schedules are refused (the captured/portable path was removed in 0.26) …") and never runs it;
|
|
331
|
-
the rest of the scope's jobs continue. `list`/`show` report its
|
|
332
|
-
`executionStatus` as `{kind:"invalid", …, reason}`.
|
|
333
|
-
- A captured attempt or job lock left mid-run by 0.25 is reported on that job
|
|
334
|
-
(`executionStatus.intent`, `reconcile` refuses with `E_SCHEDULE_INVALID`) and is
|
|
335
|
-
never run, adopted or released. A held captured lock keeps its launch slot
|
|
336
|
-
until the job is gone: remove it with `oats schedule remove --force <id>`, or
|
|
337
|
-
re-add it without the captured keys.
|
|
338
|
-
|
|
339
|
-
Every other definition is a plain one; `list`/`show` report its `executionStatus`
|
|
340
|
-
as `{kind:"legacy",capture:"unknown",migrationRequired:true}` (a released wire,
|
|
341
|
-
kept as it was).
|
|
261
|
+
- `oats sync` (or `oats automations refresh`) discovers the confirmed
|
|
262
|
+
members' definitions into `.agents/automations/snapshot.json`. A trigger
|
|
263
|
+
template (`from:`) is instantiated then, at the commit the lock pins.
|
|
264
|
+
- The host tick refreshes the snapshot when it is more than ten minutes old;
|
|
265
|
+
when a refresh fails, the last good snapshot keeps serving. A change in Git
|
|
266
|
+
reaches the named host within about ten minutes.
|
|
267
|
+
- Run state stays local to each host; a workspace schedule's lock and state
|
|
268
|
+
are keyed `<member>~<id>`.
|
|
269
|
+
|
|
270
|
+
**Writing one.** `oats trigger add` or `oats schedule add` with `--workspace
|
|
271
|
+
<member> --runs-on <host> --owner <host>/<login>` validates the file, then
|
|
272
|
+
writes `oats-triggers/<id>.yaml` or `oats-schedules/<id>.yaml` inside a
|
|
273
|
+
checkout of that member (for you to commit and push), or prints it anywhere
|
|
274
|
+
else. `oats trigger test <member>/<id>` and `oats schedule test <member>/<id>`
|
|
275
|
+
check the placement and everything else on this host.
|
|
342
276
|
|
|
343
277
|
## Commands
|
|
344
278
|
|
|
345
279
|
```sh
|
|
346
|
-
oats schedule add <id> --file spec.json --dir <
|
|
280
|
+
oats schedule add <id> --file spec.json [--dir <deployment>] [--json]
|
|
347
281
|
oats schedule update <id> --file spec.json
|
|
348
|
-
oats schedule list | show <id> | enable <id> | disable <id> | remove <id>
|
|
349
|
-
oats schedule run <id>
|
|
350
|
-
oats schedule test <id> # dry run: where it runs, whether its soul resolves, when it is next due
|
|
351
|
-
oats schedule tick --dry-run
|
|
282
|
+
oats schedule list | show <id> | enable <id> | disable <id> | remove <id> [--force]
|
|
283
|
+
oats schedule run <id> [--force] # now, under the same lock and bound
|
|
284
|
+
oats schedule test <id> # dry run: where it runs, whether its soul resolves, when it is next due
|
|
285
|
+
oats schedule tick [--dry-run] # evaluate this deployment now; --dry-run launches nothing
|
|
352
286
|
oats schedule reconcile <id> [--clear] # resolve an attempt whose result was never recorded
|
|
353
|
-
oats schedule host install # register this
|
|
287
|
+
oats schedule host install # register this deployment and install the one host timer (idempotent)
|
|
354
288
|
oats schedule host status | uninstall
|
|
355
289
|
oats spawn <agent> ... --wake-every 15 --wake-message "Anything new?" # or --wake-file spec.json
|
|
356
290
|
```
|
|
357
291
|
|
|
358
|
-
|
|
359
|
-
|
|
292
|
+
`<id>` is `local/<id>` (or the bare id) or `<member>/<id>`. `host uninstall`
|
|
293
|
+
unregisters the deployment and removes the timer once none is registered.
|
|
294
|
+
Every `oats schedule` subcommand takes `--server <id>` instead of `--dir` to
|
|
295
|
+
run on that registered server.
|
|
296
|
+
|
|
297
|
+
`oats schedule list --json` answers:
|
|
298
|
+
|
|
299
|
+
```text
|
|
300
|
+
{ scope, scheduleApi: 2, scheduleHistoryApi: 3,
|
|
301
|
+
integrity: { sources: [{ path, status, bytes }] },
|
|
302
|
+
host: { name, ghUser: { <gh host>: <login> | null } },
|
|
303
|
+
schedules: [ <row> ],
|
|
304
|
+
triggers: { count, command: "oats trigger list" },
|
|
305
|
+
snapshot: { takenAt, problems } | null,
|
|
306
|
+
scheduler: { installed, active, unit?, lastTick, maxConcurrent, tickIntervalSec,
|
|
307
|
+
workspace, registered, workspaces, live } }
|
|
308
|
+
```
|
|
360
309
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
`
|
|
310
|
+
Each row is the stored definition plus `id` (bare for a local schedule,
|
|
311
|
+
`<member>/<id>` for a workspace one), `qualifiedId`, `origin`, `owner`,
|
|
312
|
+
`runsOn`, `runsHere`, `reason`, `enabledHere`, `soul`, `nextDue`, `lastRun`,
|
|
313
|
+
`recentRuns` and `running`; an unreadable row carries `unreadable: { code,
|
|
314
|
+
message }` instead of failing the list. `scheduler.active` is what the OS
|
|
315
|
+
reports about the timer. `oats trigger list --json` carries the same
|
|
316
|
+
`scheduler`. The field-level contract is in
|
|
317
|
+
[desktop-cli-api.md](desktop-cli-api.md).
|
|
365
318
|
|
|
366
319
|
## What a run reports
|
|
367
320
|
|
|
368
|
-
`launched` (spawn or command returned), `active` (the instance is running;
|
|
369
|
-
|
|
370
|
-
`
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
unknown; check the roster and the host by hand, then
|
|
388
|
-
`oats schedule reconcile <id> --clear` records launch-failed and frees the
|
|
389
|
-
slot (or `remove --force` forgets the job).
|
|
390
|
-
|
|
391
|
-
A wake job that starts a stopped home holds a launch slot while that
|
|
392
|
-
harness is starting, active, retiring or unobservable, and releases it when
|
|
393
|
-
the harness is proven stopped (the session start receipt's exit marker for
|
|
394
|
-
that launch, or a home that no longer has a session) or the home is gone.
|
|
395
|
-
A persistent home that outlives its process does not keep a slot. Delivering
|
|
396
|
-
a message to a home that is already running takes no slot. The host tick
|
|
397
|
-
observes every registered scope first, then admits due jobs in one
|
|
398
|
-
host-wide order, least recently launched first (only an actual harness
|
|
399
|
-
launch counts; a skipped or pending job keeps its place at the front), so
|
|
400
|
-
one frequent job in one scope cannot keep the only slot forever. An invalid
|
|
401
|
-
or malformed definition is reported on that job and the rest of the tick
|
|
321
|
+
`launched` (spawn or command returned), `active` (the instance is running; a
|
|
322
|
+
home whose retirement is pending still counts), `ended` (its home is gone),
|
|
323
|
+
`stopped` (home present, nothing running: needs attention, never removed for
|
|
324
|
+
you), `launch-failed`, `unknown`, and for wake jobs `delivered`, `started` or
|
|
325
|
+
`skipped`. The kernel never claims a task succeeded.
|
|
326
|
+
|
|
327
|
+
`unknown` means the launch's side effects are unconfirmed: a command timed out
|
|
328
|
+
or answered no envelope, or an attempt was never recorded. The job keeps its
|
|
329
|
+
slot and is skipped until `oats schedule reconcile <id>`, which adopts only an
|
|
330
|
+
attributable receipt (a spawn job's instance, named for its minute, or the
|
|
331
|
+
instance a command's answer named). When nothing is attributable, check the
|
|
332
|
+
roster and the host by hand, then `reconcile <id> --clear` records
|
|
333
|
+
`launch-failed` and frees the slot.
|
|
334
|
+
|
|
335
|
+
**Slots.** A wake job that starts a stopped home holds a launch slot until the
|
|
336
|
+
harness is proven stopped or the home is gone; delivering to a running home
|
|
337
|
+
takes none. The host tick admits due jobs in one host-wide order, least
|
|
338
|
+
recently launched first, so one frequent job cannot keep the only slot
|
|
339
|
+
forever. An invalid definition is reported on its job; the rest of the tick
|
|
402
340
|
continues.
|
|
403
341
|
|
|
404
|
-
`disable` never stops anything. `update` never touches a
|
|
405
|
-
and while a job holds a slot or has an unresolved attempt
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
observation releases it once the harness is proven stopped or absent, one tick
|
|
411
|
-
at worst.
|
|
412
|
-
`remove` refuses while the job's instance is still tracked (`--force`
|
|
413
|
-
forgets the job without stopping anything). Retiring an instance removes the
|
|
414
|
-
wake jobs bound to its home; a wake whose home is gone otherwise stays
|
|
415
|
-
listed with its skipped reason.
|
|
342
|
+
**Changing a job.** `disable` never stops anything. `update` never touches a
|
|
343
|
+
running instance, and while a job holds a slot or has an unresolved attempt
|
|
344
|
+
only `cron`, `tz` and `enabled` can change. `remove` refuses while the job's
|
|
345
|
+
instance is tracked or its effects are unresolved (`--force` forgets the job
|
|
346
|
+
without stopping anything). Retiring an instance removes the wake jobs bound
|
|
347
|
+
to its home.
|
|
416
348
|
|
|
417
349
|
## Wake at spawn
|
|
418
350
|
|
|
419
|
-
`oats spawn ... --wake-file <
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
carries the
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
##
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
oats
|
|
457
|
-
oats okf setup --source /absolute/state/sources/UUID/source.json --soul domain-expert --json
|
|
458
|
-
# Explicit host change; never part of a scaffold-only test:
|
|
459
|
-
oats okf setup --source /absolute/state/sources/UUID/source.json --install-host --soul domain-expert --json
|
|
460
|
-
# Definition-only disable; does not stop a worker or reconcile an executing job:
|
|
461
|
-
oats okf setup --source /absolute/state/sources/UUID/source.json --disable --soul domain-expert --json
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
Retirement captures/enqueues final evidence and does not synchronously remove
|
|
465
|
-
its job under the scheduler's host lock or wait for a model/GitHub. A drained
|
|
466
|
-
retired source returns empty; disable its job explicitly when appropriate.
|
|
467
|
-
Source no-launch guards prevent automatic model starts, and final capture of
|
|
468
|
-
a no-launch source disables its automatic processing. `inspect` distinguishes
|
|
469
|
-
job definition from actual timer activity; an absent or inactive timer is not
|
|
470
|
-
reported as enabled automation. The scheduler's launch/liveness receipts do not
|
|
471
|
-
replace OKF's processing, delivery and merge-visible acceptance receipts.
|
|
351
|
+
`oats spawn ... --wake-file <JSON {cron, tz, message, enabled}>` (or
|
|
352
|
+
`--wake-every N --wake-message <text>`) saves a local wake job
|
|
353
|
+
`wake-<instance>` bound to the new home once the spawn succeeds. If the save
|
|
354
|
+
fails, the spawn result still carries the instance receipt, plus
|
|
355
|
+
`wakeScheduleError` and a warning.
|
|
356
|
+
|
|
357
|
+
## Knowledge harvest jobs
|
|
358
|
+
|
|
359
|
+
oats.okf uses both mechanisms. The flow, the harvest switch and the package
|
|
360
|
+
souls are described in [knowledge.md](knowledge.md#knowledge-operations).
|
|
361
|
+
|
|
362
|
+
- **Harvest.** A source exists only where harvest is on (`oats-local.yaml`
|
|
363
|
+
`settings.oats.okf.harvest: on`; default off). oats.okf then registers one
|
|
364
|
+
local **command job per source**, `okf-<source id>`, which runs from the
|
|
365
|
+
deployment with argv equivalent to:
|
|
366
|
+
|
|
367
|
+
```text
|
|
368
|
+
oats okf run-source --source /absolute/state/sources/UUID/source.json --soul domain-expert --json
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
The job spawns the package soul `oats.okf/knowledge-harvester`. The source's
|
|
372
|
+
evidence lives outside its home, so the job keeps working after the source
|
|
373
|
+
instance retires; once a retired source is drained, oats.okf removes the
|
|
374
|
+
job. Registration never re-enables a disabled job.
|
|
375
|
+
`oats schedule disable okf-<source id>` is the emergency brake for one
|
|
376
|
+
source.
|
|
377
|
+
- **Review.** Each harvest PR is reviewed by a new
|
|
378
|
+
`oats.okf/knowledge-maintainer`, spawned by a trigger from the package
|
|
379
|
+
template `oats.okf:harvest-review`: a workspace file
|
|
380
|
+
(`oats-triggers/okf-harvest-review.yaml`) or a local `oats trigger add
|
|
381
|
+
--from oats.okf:harvest-review`.
|
|
382
|
+
|
|
383
|
+
Registering a source never installs the host timer. `oats okf inspect
|
|
384
|
+
--source <source.json> --soul <soul>` reports the job and whether the timer is
|
|
385
|
+
actually active; `oats okf setup --source <source.json> --soul <soul>
|
|
386
|
+
--install-host` installs it, and `--disable` disables the job without
|
|
387
|
+
stopping a running worker. The scheduler's launch receipts do not replace
|
|
388
|
+
oats.okf's own processing, delivery and acceptance receipts.
|