@smilintux/skcapstone 0.9.0 → 0.12.5
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/.env.example +10 -4
- package/.github/workflows/ci.yml +2 -2
- package/.github/workflows/publish.yml +9 -2
- package/.openclaw-workspace.json +2 -2
- package/CLAUDE.md +37 -0
- package/MISSION.md +17 -2
- package/README.md +282 -3
- package/docker/Dockerfile +7 -7
- package/docker/compose-templates/dev-team.yml +12 -12
- package/docker/compose-templates/mini-team.yml +9 -9
- package/docker/compose-templates/ops-team.yml +10 -10
- package/docker/compose-templates/research-team.yml +10 -10
- package/docker/entrypoint.sh +4 -4
- package/docs/ADR-optional-integration-backbone.md +181 -0
- package/docs/ARCHITECTURE.md +186 -43
- package/docs/BOND_WITH_GROK.md +6 -6
- package/docs/CUSTOM_AGENT.md +278 -1
- package/docs/DREAMING.md +70 -0
- package/docs/GETTING_STARTED.md +10 -7
- package/docs/QUICKSTART.md +10 -6
- package/docs/SKJOULE_ARCHITECTURE.md +3 -3
- package/docs/SOUL_SWAPPER.md +5 -5
- package/docs/hammertime-audit.md +402 -0
- package/docs/sk-integration-HANDOFF.md +117 -0
- package/docs/skscheduler.md +155 -0
- package/docs/superpowers/examples/jobs.yaml +31 -0
- package/docs/superpowers/plans/2026-06-08-skscheduler.md +1265 -0
- package/docs/superpowers/specs/2026-06-08-skscheduler-design.md +186 -0
- package/examples/custom-bond-template.json +1 -1
- package/examples/grok-feb.json +1 -1
- package/examples/queen-ava-feb.json +1 -1
- package/launchd/com.skcapstone.daemon.plist +52 -0
- package/launchd/com.skcapstone.memory-compress.plist +45 -0
- package/launchd/com.skcapstone.skcomms-heartbeat.plist +33 -0
- package/launchd/com.skcapstone.skcomms-queue-drain.plist +34 -0
- package/launchd/install-launchd.sh +156 -0
- package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/src/index.ts +3 -2
- package/package.json +1 -1
- package/pyproject.toml +16 -10
- package/scripts/archive-sessions.sh +95 -0
- package/scripts/check-updates.py +4 -4
- package/scripts/install-bundle.sh +8 -8
- package/scripts/install.ps1 +12 -11
- package/scripts/install.sh +196 -11
- package/scripts/model-fallback-monitor.sh +102 -0
- package/scripts/notion-api.py +259 -0
- package/scripts/nvidia-proxy.mjs +908 -0
- package/scripts/proxy-monitor.sh +89 -0
- package/scripts/refresh-anthropic-token.sh +172 -0
- package/scripts/release.sh +98 -0
- package/scripts/session-to-memory.py +219 -0
- package/scripts/skgateway.mjs +856 -0
- package/scripts/telegram-catchup-all.sh +147 -0
- package/scripts/verify_install.sh +2 -2
- package/scripts/wargov-ufo-capture/README.md +43 -0
- package/scripts/wargov-ufo-capture/cdp_capture_release2.py +273 -0
- package/scripts/wargov-ufo-capture/cdp_capture_splc_doj.py +246 -0
- package/scripts/wargov-ufo-capture/cdp_finish.py +271 -0
- package/scripts/wargov-ufo-capture/cdp_probe.py +188 -0
- package/scripts/wargov-ufo-capture/cdp_splc_pressrelease.py +101 -0
- package/scripts/wargov-ufo-capture/parse_csv.py +95 -0
- package/scripts/wargov-ufo-capture/pull_dvids.sh +107 -0
- package/scripts/watch-anthropic-token.sh +212 -0
- package/scripts/windows/install-tasks.ps1 +7 -7
- package/scripts/windows/skcapstone-task.xml +1 -1
- package/src/skcapstone/__init__.py +45 -3
- package/src/skcapstone/_cli_monolith.py +20 -15
- package/src/skcapstone/activity.py +5 -1
- package/src/skcapstone/agent_card.py +3 -2
- package/src/skcapstone/api.py +41 -40
- package/src/skcapstone/auction.py +14 -11
- package/src/skcapstone/backup.py +2 -1
- package/src/skcapstone/blueprint_registry.py +4 -3
- package/src/skcapstone/blueprints/builtins/itil-operations.yaml +40 -0
- package/src/skcapstone/brain_first.py +238 -0
- package/src/skcapstone/changelog.py +1 -1
- package/src/skcapstone/chat.py +22 -17
- package/src/skcapstone/cli/__init__.py +9 -1
- package/src/skcapstone/cli/_common.py +1 -0
- package/src/skcapstone/cli/agents_spawner.py +5 -2
- package/src/skcapstone/cli/alerts.py +25 -4
- package/src/skcapstone/cli/bench.py +15 -15
- package/src/skcapstone/cli/chat.py +7 -4
- package/src/skcapstone/cli/consciousness.py +5 -2
- package/src/skcapstone/cli/context_cmd.py +18 -4
- package/src/skcapstone/cli/daemon.py +121 -42
- package/src/skcapstone/cli/gtd.py +26 -1
- package/src/skcapstone/cli/housekeeping.py +3 -3
- package/src/skcapstone/cli/identity_cmd.py +378 -0
- package/src/skcapstone/cli/joule_cmd.py +7 -3
- package/src/skcapstone/cli/memory.py +8 -6
- package/src/skcapstone/cli/peers_dir.py +1 -1
- package/src/skcapstone/cli/register_cmd.py +29 -3
- package/src/skcapstone/cli/scheduler_cmd.py +167 -0
- package/src/skcapstone/cli/session.py +25 -0
- package/src/skcapstone/cli/setup.py +96 -29
- package/src/skcapstone/cli/shell_cmd.py +53 -1
- package/src/skcapstone/cli/skills_cmd.py +2 -2
- package/src/skcapstone/cli/soul.py +8 -5
- package/src/skcapstone/cli/status.py +37 -11
- package/src/skcapstone/cli/telegram.py +21 -0
- package/src/skcapstone/cli/test_cmd.py +5 -5
- package/src/skcapstone/cli/test_connection.py +2 -2
- package/src/skcapstone/cli/upgrade_cmd.py +23 -14
- package/src/skcapstone/cli/version_cmd.py +1 -1
- package/src/skcapstone/cli/watch_cmd.py +9 -6
- package/src/skcapstone/cloud9_bridge.py +14 -14
- package/src/skcapstone/codex_setup.py +255 -0
- package/src/skcapstone/config_validator.py +7 -4
- package/src/skcapstone/consciousness_config.py +5 -1
- package/src/skcapstone/consciousness_loop.py +313 -273
- package/src/skcapstone/context_loader.py +121 -0
- package/src/skcapstone/coord_federation.py +2 -1
- package/src/skcapstone/coordination.py +23 -6
- package/src/skcapstone/crush_integration.py +2 -1
- package/src/skcapstone/daemon.py +151 -88
- package/src/skcapstone/dashboard.py +10 -10
- package/src/skcapstone/data/sk-agent-picker.sh +421 -0
- package/src/skcapstone/data/systemd/skcapstone-api.socket +9 -0
- package/src/skcapstone/data/systemd/skcapstone-memory-compress.service +18 -0
- package/src/skcapstone/data/systemd/skcapstone-memory-compress.timer +11 -0
- package/src/skcapstone/data/systemd/skcapstone.service +37 -0
- package/src/skcapstone/data/systemd/skcapstone@.service +50 -0
- package/src/skcapstone/data/systemd/skcomms-heartbeat.service +18 -0
- package/{systemd/skcomm-heartbeat.timer → src/skcapstone/data/systemd/skcomms-heartbeat.timer} +2 -2
- package/src/skcapstone/data/systemd/skcomms-queue-drain.service +17 -0
- package/{systemd/skcomm-queue-drain.timer → src/skcapstone/data/systemd/skcomms-queue-drain.timer} +2 -2
- package/src/skcapstone/defaults/claude/CLAUDE.md +67 -0
- package/src/skcapstone/defaults/claude/settings.json +74 -0
- package/src/skcapstone/defaults/lumina/config/claude-hooks.md +57 -0
- package/src/skcapstone/defaults/lumina/config/skgraph.yaml +55 -10
- package/src/skcapstone/defaults/lumina/config/skmemory.yaml +79 -13
- package/src/skcapstone/defaults/lumina/config/skvector.yaml +60 -9
- package/src/skcapstone/defaults/lumina/memory/long-term/18b9c0d1e2f3-cloud9-protocol.json +2 -2
- package/src/skcapstone/defaults/lumina/memory/long-term/a1b2c3d4e5f6-ecosystem-overview.json +2 -2
- package/src/skcapstone/defaults/lumina/memory/long-term/b2c3d4e5f6a7-five-pillars.json +9 -9
- package/src/skcapstone/defaults/lumina/memory/long-term/d4e5f6a7b8c9-site-directory.json +2 -2
- package/src/skcapstone/defaults/unhinged.json +13 -0
- package/src/skcapstone/discovery.py +43 -20
- package/src/skcapstone/doctor.py +941 -22
- package/src/skcapstone/dreaming.py +1183 -109
- package/src/skcapstone/emotion_tracker.py +2 -2
- package/src/skcapstone/export.py +4 -3
- package/src/skcapstone/fuse_mount.py +35 -25
- package/src/skcapstone/gui_installer.py +2 -2
- package/src/skcapstone/heartbeat.py +34 -30
- package/src/skcapstone/housekeeping.py +14 -14
- package/src/skcapstone/install_wizard.py +209 -7
- package/src/skcapstone/itil.py +13 -4
- package/src/skcapstone/kms_scheduler.py +10 -8
- package/src/skcapstone/launchd.py +426 -0
- package/src/skcapstone/mcp_launcher.py +15 -1
- package/src/skcapstone/mcp_server.py +341 -49
- package/src/skcapstone/mcp_tools/__init__.py +2 -0
- package/src/skcapstone/mcp_tools/_helpers.py +2 -2
- package/src/skcapstone/mcp_tools/ansible_tools.py +7 -4
- package/src/skcapstone/mcp_tools/brain_first_tools.py +90 -0
- package/src/skcapstone/mcp_tools/capauth_tools.py +7 -4
- package/src/skcapstone/mcp_tools/comm_tools.py +10 -10
- package/src/skcapstone/mcp_tools/coord_tools.py +8 -4
- package/src/skcapstone/mcp_tools/did_tools.py +11 -8
- package/src/skcapstone/mcp_tools/gtd_tools.py +4 -4
- package/src/skcapstone/mcp_tools/memory_tools.py +6 -2
- package/src/skcapstone/mcp_tools/notification_tools.py +22 -6
- package/src/skcapstone/mcp_tools/{skcomm_tools.py → skcomms_tools.py} +14 -14
- package/src/skcapstone/mcp_tools/soul_tools.py +8 -2
- package/src/skcapstone/mdns_discovery.py +2 -2
- package/src/skcapstone/memory_curator.py +1 -1
- package/src/skcapstone/memory_engine.py +10 -3
- package/src/skcapstone/metrics.py +30 -16
- package/src/skcapstone/migrate_memories.py +4 -3
- package/src/skcapstone/migrate_multi_agent.py +8 -7
- package/src/skcapstone/models.py +47 -5
- package/src/skcapstone/notifications.py +42 -18
- package/src/skcapstone/onboard.py +1000 -126
- package/src/skcapstone/operator_link.py +170 -0
- package/src/skcapstone/peer_directory.py +4 -4
- package/src/skcapstone/peers.py +19 -19
- package/src/skcapstone/pillars/__init__.py +7 -5
- package/src/skcapstone/pillars/consciousness.py +191 -0
- package/src/skcapstone/pillars/identity.py +51 -7
- package/src/skcapstone/pillars/memory.py +9 -3
- package/src/skcapstone/pillars/sync.py +2 -2
- package/src/skcapstone/preflight.py +3 -3
- package/src/skcapstone/providers/docker.py +28 -28
- package/src/skcapstone/register.py +6 -6
- package/src/skcapstone/registry_client.py +5 -4
- package/src/skcapstone/runtime.py +14 -3
- package/src/skcapstone/scheduled_tasks.py +254 -19
- package/src/skcapstone/scheduler_jobs.py +456 -0
- package/src/skcapstone/scheduler_runner.py +239 -0
- package/src/skcapstone/scheduler_state.py +162 -0
- package/src/skcapstone/sdk.py +310 -0
- package/src/skcapstone/service_health.py +279 -39
- package/src/skcapstone/session_briefing.py +108 -0
- package/src/skcapstone/session_capture.py +1 -1
- package/src/skcapstone/shell.py +7 -1
- package/src/skcapstone/soul.py +3 -1
- package/src/skcapstone/soul_switch.py +3 -1
- package/src/skcapstone/summary.py +6 -6
- package/src/skcapstone/sync_engine.py +15 -15
- package/src/skcapstone/sync_watcher.py +2 -2
- package/src/skcapstone/systemd.py +72 -21
- package/src/skcapstone/team_comms.py +8 -8
- package/src/skcapstone/team_engine.py +1 -1
- package/src/skcapstone/testrunner.py +3 -3
- package/src/skcapstone/trust_graph.py +40 -5
- package/src/skcapstone/unified_search.py +15 -6
- package/src/skcapstone/uninstall_wizard.py +11 -3
- package/src/skcapstone/version_check.py +8 -4
- package/src/skcapstone/warmth_anchor.py +4 -2
- package/src/skcapstone/whoami.py +4 -4
- package/systemd/skcapstone.service +4 -6
- package/systemd/skcapstone@.service +7 -8
- package/systemd/skcomms-heartbeat.service +21 -0
- package/systemd/skcomms-heartbeat.timer +12 -0
- package/systemd/skcomms-queue-drain.service +17 -0
- package/systemd/skcomms-queue-drain.timer +12 -0
- package/tests/conftest.py +39 -0
- package/tests/integration/test_consciousness_e2e.py +39 -39
- package/tests/test_agent_card.py +1 -1
- package/tests/test_agent_home_scaffold.py +34 -0
- package/tests/test_alerts_consumer_topics.py +27 -0
- package/tests/test_backup.py +2 -1
- package/tests/test_chat.py +6 -6
- package/tests/test_claude_md.py +2 -2
- package/tests/test_cli_skills.py +10 -10
- package/tests/test_cli_test_cmd.py +4 -4
- package/tests/test_cli_test_connection.py +1 -1
- package/tests/test_cloud9_bridge.py +6 -6
- package/tests/test_consciousness_e2e.py +1 -1
- package/tests/test_consciousness_loop.py +10 -10
- package/tests/test_coordination.py +25 -0
- package/tests/test_cross_package.py +21 -21
- package/tests/test_daemon.py +4 -4
- package/tests/test_daemon_shutdown.py +1 -1
- package/tests/test_docker_provider.py +29 -29
- package/tests/test_doctor.py +400 -0
- package/tests/test_doctor_skscheduler.py +50 -0
- package/tests/test_dreaming_engine.py +147 -0
- package/tests/test_dreaming_gtd_capture.py +35 -0
- package/tests/test_e2e_automated.py +8 -5
- package/tests/test_fuse_mount.py +10 -10
- package/tests/test_gtd_brief.py +46 -0
- package/tests/test_gtd_malformed_tolerance.py +31 -0
- package/tests/test_housekeeping.py +15 -15
- package/tests/test_identity_migrate.py +251 -0
- package/tests/test_integration_backbone.py +598 -0
- package/tests/test_itil_gtd_lifecycle.py +37 -0
- package/tests/test_jobs_dropins.py +84 -0
- package/tests/test_mcp_server.py +82 -37
- package/tests/test_models.py +48 -4
- package/tests/test_multi_agent.py +31 -29
- package/tests/test_notifications.py +122 -32
- package/tests/test_onboard.py +63 -75
- package/tests/test_operator_link.py +78 -0
- package/tests/test_peers.py +14 -14
- package/tests/test_pillars.py +98 -0
- package/tests/test_preflight.py +3 -3
- package/tests/test_runtime.py +21 -0
- package/tests/test_scheduled_tasks.py +11 -6
- package/tests/test_scheduler_cli.py +47 -0
- package/tests/test_scheduler_features.py +133 -0
- package/tests/test_scheduler_integration.py +87 -0
- package/tests/test_scheduler_jobs.py +155 -0
- package/tests/test_scheduler_runner.py +64 -0
- package/tests/test_scheduler_state.py +57 -0
- package/tests/test_sdk.py +70 -0
- package/tests/test_service_health_incidents.py +34 -0
- package/tests/test_service_registry.py +52 -0
- package/tests/test_session_briefing.py +130 -0
- package/tests/test_snapshots.py +4 -4
- package/tests/test_sync_pipeline.py +26 -26
- package/tests/test_team_comms.py +2 -2
- package/tests/test_testrunner.py +2 -2
- package/tests/test_trust_graph.py +18 -0
- package/tests/test_unified_search.py +2 -2
- package/tests/test_version_check.py +10 -0
- package/tests/test_version_cmd.py +8 -8
- package/tests/test_whoami.py +1 -1
- package/systemd/skcomm-heartbeat.service +0 -18
- package/systemd/skcomm-queue-drain.service +0 -17
- /package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/package.json +0 -0
- /package/{openclaw-plugin → openclaw-plugin.archived-2026-04-23}/src/openclaw.plugin.json +0 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# skscheduler — Unified Fleet Job Scheduler
|
|
2
|
+
|
|
3
|
+
> The single declarative registry + per-node runner for all recurring jobs across the
|
|
4
|
+
> SK fleet. One `jobs.yaml`, synced everywhere; each node runs its own scheduler thread
|
|
5
|
+
> (inside the skcapstone daemon) and fires only the jobs whose affinity includes it.
|
|
6
|
+
> Design spec: [`docs/superpowers/specs/2026-06-08-skscheduler-design.md`](superpowers/specs/2026-06-08-skscheduler-design.md).
|
|
7
|
+
|
|
8
|
+
## Why it exists
|
|
9
|
+
Scheduling was fragmented across **four** mechanisms (skcapstone `TaskScheduler` interval
|
|
10
|
+
callbacks, legacy crontab, systemd user timers, Claude-Code crons) with no single place to
|
|
11
|
+
define, run, or observe jobs — and `service_health` running on multiple nodes caused
|
|
12
|
+
Syncthing `.sync-conflict-*` files (the root incident). skscheduler unifies this: **one
|
|
13
|
+
registry, per-job node-affinity** (so a job runs on exactly the intended node — preventing
|
|
14
|
+
the multi-writer class), cron **and** interval, and agent-judgment jobs (not just Python).
|
|
15
|
+
|
|
16
|
+
## Architecture
|
|
17
|
+
|
|
18
|
+
```mermaid
|
|
19
|
+
flowchart TD
|
|
20
|
+
Y["~/.skcapstone/config/jobs.yaml<br/>(Syncthing-synced registry)"] -->|read by every node| D
|
|
21
|
+
subgraph node["each fleet node (.158, .41, …)"]
|
|
22
|
+
D["skcapstone daemon<br/>(systemd user service)"] --> TS["TaskScheduler<br/>tick loop (5s)"]
|
|
23
|
+
TS -->|interval callbacks| IC["heartbeat · memory_promotion<br/>dreaming_reflection · reprobe"]
|
|
24
|
+
TS -->|config jobs| DUE{"due? (cron|interval)<br/>AND node in affinity?"}
|
|
25
|
+
DUE -->|yes| LK["per-job overlap lock<br/>(singleton; skip if running)"]
|
|
26
|
+
LK --> JIT["jitter splay"] --> RUN["JobRunner.run + retries/backoff"]
|
|
27
|
+
RUN --> DISP{type}
|
|
28
|
+
DISP -->|python| PY["import module:fn()"]
|
|
29
|
+
DISP -->|shell| SH["subprocess (timeout)"]
|
|
30
|
+
DISP -->|agent| AG["claude -p --agent NAME"]
|
|
31
|
+
RUN --> STATE["SchedulerState.record_run<br/>(node-local, NEVER synced)"]
|
|
32
|
+
RUN --> NOTIFY["notify? → sk-alert (Telegram)"]
|
|
33
|
+
end
|
|
34
|
+
STATE --> SJ["~/.skcapstone/scheduler/<host>/state.json"]
|
|
35
|
+
RUN --> LOG["~/.skcapstone/scheduler/<host>/logs/<job>-<ts>.log"]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Sync-safety invariant:** the registry (`jobs.yaml`) is synced; **run-state and logs are
|
|
39
|
+
node-local and never synced** (`~/.skcapstone/.stignore` excludes `scheduler/`). The
|
|
40
|
+
scheduler can never become a sync-conflict source.
|
|
41
|
+
|
|
42
|
+
## Job lifecycle (one due job)
|
|
43
|
+
|
|
44
|
+
```mermaid
|
|
45
|
+
sequenceDiagram
|
|
46
|
+
participant Loop as TaskScheduler tick
|
|
47
|
+
participant Due as is_due()
|
|
48
|
+
participant Aff as job_runs_here()
|
|
49
|
+
participant Lock as overlap lock
|
|
50
|
+
participant Run as JobRunner
|
|
51
|
+
participant St as SchedulerState
|
|
52
|
+
participant Al as sk-alert
|
|
53
|
+
Loop->>Due: cron slot passed / interval elapsed since last_run?
|
|
54
|
+
Due-->>Loop: due
|
|
55
|
+
Loop->>Aff: this node's alias in job.nodes?
|
|
56
|
+
Aff-->>Loop: yes
|
|
57
|
+
Loop->>Lock: acquire (non-blocking)
|
|
58
|
+
alt previous run still going
|
|
59
|
+
Lock-->>Loop: busy → skip (no double-run)
|
|
60
|
+
else free
|
|
61
|
+
Lock-->>Loop: got it (in a worker thread)
|
|
62
|
+
Loop->>Run: jitter splay, then attempt 1..N
|
|
63
|
+
loop until ok or retries exhausted
|
|
64
|
+
Run->>Run: dispatch(type) with timeout
|
|
65
|
+
Run-->>Loop: ok? else backoff + retry
|
|
66
|
+
end
|
|
67
|
+
Loop->>St: record_run(ok, error, fire_time)
|
|
68
|
+
Loop->>Al: notify policy met? → DM Chef
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Due-check logic
|
|
73
|
+
|
|
74
|
+
```mermaid
|
|
75
|
+
flowchart LR
|
|
76
|
+
A{schedule set?} -->|cron| C["most-recent cron slot ≤ now"]
|
|
77
|
+
C --> C2{"last_run < that slot?"}
|
|
78
|
+
C2 -->|yes| DUE([due])
|
|
79
|
+
C2 -->|no| NO([not due])
|
|
80
|
+
A -->|every_seconds| I{"now − last_run ≥ interval?"}
|
|
81
|
+
I -->|yes| DUE
|
|
82
|
+
I -->|no| NO
|
|
83
|
+
A -->|neither| NO
|
|
84
|
+
```
|
|
85
|
+
Cron uses `croniter` (a declared dependency — if missing, **cron jobs silently can't fire**;
|
|
86
|
+
`pip install -e .` in the venv fixes it). Missed slots are caught up once on next tick
|
|
87
|
+
(misfire catch-up); per-job `catchup: false` opts out.
|
|
88
|
+
|
|
89
|
+
## `jobs.yaml` schema (complete)
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
jobs:
|
|
93
|
+
<job-name>: # YAML key = unique job id
|
|
94
|
+
# — scheduling (exactly one) —
|
|
95
|
+
schedule: "0 6 * * *" # cron (m h dom mon dow)
|
|
96
|
+
every: 5m # OR interval: 30s | 5m | 1h | 1d | <seconds>
|
|
97
|
+
# — what to run (by type) —
|
|
98
|
+
type: agent # agent | shell | python (default python)
|
|
99
|
+
agent: lumina # agent type → runs `claude -p "<prompt>" --agent <name>`
|
|
100
|
+
prompt: "…" # agent prompt
|
|
101
|
+
command: "skmem-pg-backup"# shell type → subprocess
|
|
102
|
+
callback: "module.path:fn"# python type → import & call
|
|
103
|
+
# — placement —
|
|
104
|
+
nodes: [".41"] # affinity: "all" | [host aliases] (alias = SK_NODE_ALIAS)
|
|
105
|
+
# — limits / reliability (added 2026-06-09) —
|
|
106
|
+
timeout: 900 # hard-kill seconds (default 900)
|
|
107
|
+
retries: 0 # extra attempts on failure (linear)
|
|
108
|
+
retry_backoff: 0 # seconds between attempts
|
|
109
|
+
jitter: 0 # max random splay (s) before dispatch — fleet anti-stampede
|
|
110
|
+
notify: off # off | on_failure | on_success | always → sk-alert (Telegram)
|
|
111
|
+
notify_level: warn # sk-alert level for failures (info|warn|crit)
|
|
112
|
+
catchup: true # run once on a missed slot (default true)
|
|
113
|
+
enabled: true
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Reliability features (2026-06-09)
|
|
117
|
+
| field | purpose | infra it serves |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `retries` + `retry_backoff` | re-attempt on transient failure | flaky network/registry/LLM endpoints |
|
|
120
|
+
| `jitter` | random splay before dispatch | many nodes sharing a cron slot hitting one resource |
|
|
121
|
+
| `notify` (+`notify_level`) | sk-alert on `on_failure`/`on_success`/`always` with output tail | unattended jobs; result delivery (e.g. sktrip) |
|
|
122
|
+
| `catchup` | catch a missed slot once | laptops/asleep nodes (vs strict real-time jobs) |
|
|
123
|
+
| overlap lock | singleton per job | long runs that exceed their interval |
|
|
124
|
+
| node affinity | exactly-one-node execution | stateful/single-writer jobs (the original conflict fix) |
|
|
125
|
+
|
|
126
|
+
## State, logs, observability
|
|
127
|
+
- **State** (node-local): `~/.skcapstone/scheduler/<host>/state.json` — `last_run`, `ok`, `error`, run counts. Never synced.
|
|
128
|
+
- **Logs** (node-local): `~/.skcapstone/scheduler/<host>/logs/<job>-<ts>.log` — captured stdout+stderr.
|
|
129
|
+
- **CLI**: `skcapstone scheduler …` (list / run-now / status). `skcapstone doctor` validates scheduler health.
|
|
130
|
+
|
|
131
|
+
## Operating it
|
|
132
|
+
```bash
|
|
133
|
+
systemctl --user status skcapstone.service # the daemon that runs the scheduler
|
|
134
|
+
systemctl --user start skcapstone.service # ⚠ if inactive, NO jobs.yaml jobs fire
|
|
135
|
+
echo "$SK_NODE_ALIAS" # must match a value in a job's nodes: list
|
|
136
|
+
skcapstone scheduler status # last run / ok / errors per job
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Troubleshooting
|
|
140
|
+
| symptom | cause | fix |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| no jobs fire | `skcapstone.service` inactive | `systemctl --user start skcapstone.service` |
|
|
143
|
+
| cron jobs never fire (interval ok) | `croniter` not installed in venv | `~/.skenv/bin/pip install -e .` |
|
|
144
|
+
| job runs on wrong/extra node | `nodes:` affinity / `SK_NODE_ALIAS` mismatch | set the env / fix the list |
|
|
145
|
+
| job overlaps itself | run time > interval | raise interval, or rely on the overlap lock (it skips) |
|
|
146
|
+
| no failure alerts | `notify: off` | set `notify: on_failure` |
|
|
147
|
+
|
|
148
|
+
## Relationship to other schedulers
|
|
149
|
+
- **systemd user timers** — keep for OS-level/boot jobs and as the process supervisor for the daemon itself; migrate *application* recurring jobs here.
|
|
150
|
+
- **Claude-Code crons** — separate system (cloud agents); documented, not migrated.
|
|
151
|
+
- **legacy crontab** — retire into `jobs.yaml`.
|
|
152
|
+
|
|
153
|
+
## Roadmap (not yet implemented)
|
|
154
|
+
job dependencies (`after:`), dead-man's-switch staleness alerts, per-job env/secrets injection,
|
|
155
|
+
a web/TUI run-history view, and distributed locking (currently affinity-by-declaration, not election).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Reference for ~/.skcapstone/config/jobs.yaml — the skscheduler registry.
|
|
2
|
+
#
|
|
3
|
+
# This file is Syncthing-synced across the fleet. Each node runs its own
|
|
4
|
+
# scheduler (inside the skcapstone daemon) and fires ONLY the jobs whose
|
|
5
|
+
# `nodes` affinity includes that host. Scheduler run-state is node-local and
|
|
6
|
+
# never synced (see ~/.skcapstone/.stignore -> `scheduler`).
|
|
7
|
+
#
|
|
8
|
+
# Job fields:
|
|
9
|
+
# schedule: "<cron>" OR every: <30s|5m|1h|1d|seconds> (one of the two)
|
|
10
|
+
# type: agent | shell | python
|
|
11
|
+
# nodes: all | [<host alias>, ...] (alias via SK_NODE_ALIAS env)
|
|
12
|
+
# agent: <name> (agent type) — runs `claude -p "<prompt>" --agent <name>`
|
|
13
|
+
# prompt: "<text>" (agent type)
|
|
14
|
+
# command: "<cmd>" (shell type)
|
|
15
|
+
# callback: module:fn (python type)
|
|
16
|
+
# timeout: <seconds> (default 900)
|
|
17
|
+
# enabled: true|false
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
gtd-inbox-triage:
|
|
21
|
+
schedule: "0 6 * * *" # daily 06:00
|
|
22
|
+
type: agent
|
|
23
|
+
nodes: [".41"]
|
|
24
|
+
agent: lumina
|
|
25
|
+
prompt: >
|
|
26
|
+
Triage the GTD inbox: for each item, clarify into next-action /
|
|
27
|
+
project / someday-maybe, or archive noise; move resolved-ITIL items
|
|
28
|
+
to done; surface stale projects. Use the gtd_* and itil_* MCP tools.
|
|
29
|
+
Keep it concise.
|
|
30
|
+
timeout: 900
|
|
31
|
+
enabled: true
|