@llblab/pi-kit 0.3.2 → 0.5.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/AGENTS.md +3 -3
- package/BACKLOG.md +1 -1
- package/CHANGELOG.md +10 -0
- package/README.md +19 -10
- package/node_modules/@llblab/pi-actors/AGENTS.md +1 -0
- package/node_modules/@llblab/pi-actors/CHANGELOG.md +6 -0
- package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +16 -6
- package/node_modules/@llblab/pi-actors/dist/skills/music-player/SKILL.md +3 -3
- package/node_modules/@llblab/pi-actors/dist/skills/music-player/genapps/music-player.mjs +6 -4
- package/node_modules/@llblab/pi-actors/dist/skills/music-player/scripts/playback.mjs +85 -18
- package/node_modules/@llblab/pi-actors/dist/skills/swarm/SKILL.md +2 -6
- package/node_modules/@llblab/pi-actors/dist/skills/swarm/references/development-swarm.md +2 -31
- package/node_modules/@llblab/pi-actors/docs/recipe-library.md +1 -1
- package/node_modules/@llblab/pi-actors/package.json +1 -1
- package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +16 -6
- package/node_modules/@llblab/pi-actors/skills/music-player/SKILL.md +3 -3
- package/node_modules/@llblab/pi-actors/skills/music-player/genapps/music-player.mjs +6 -4
- package/node_modules/@llblab/pi-actors/skills/music-player/scripts/playback.mjs +85 -18
- package/node_modules/@llblab/pi-actors/skills/swarm/SKILL.md +2 -6
- package/node_modules/@llblab/pi-actors/skills/swarm/references/development-swarm.md +2 -31
- package/node_modules/@llblab/pi-clean-room/AGENTS.md +5 -0
- package/node_modules/@llblab/pi-clean-room/BACKLOG.md +3 -0
- package/node_modules/@llblab/pi-clean-room/CHANGELOG.md +15 -0
- package/node_modules/@llblab/pi-clean-room/README.md +61 -0
- package/node_modules/@llblab/pi-clean-room/banner.jpg +0 -0
- package/node_modules/@llblab/pi-clean-room/index.ts +178 -0
- package/node_modules/@llblab/pi-clean-room/package.json +53 -0
- package/node_modules/@llblab/pi-grow-loop/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +4 -0
- package/node_modules/@llblab/pi-grow-loop/package.json +1 -1
- package/node_modules/@llblab/pi-grow-loop/skills/grow-loop/SKILL.md +3 -17
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +28 -0
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +3 -0
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +79 -0
- package/node_modules/@llblab/pi-state-flow/README.md +197 -0
- package/node_modules/@llblab/pi-state-flow/index.ts +4 -0
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +88 -0
- package/node_modules/@llblab/pi-state-flow/lib/episode.ts +29 -0
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +238 -0
- package/node_modules/@llblab/pi-state-flow/lib/json.ts +78 -0
- package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +38 -0
- package/node_modules/@llblab/pi-state-flow/lib/session.ts +49 -0
- package/node_modules/@llblab/pi-state-flow/lib/skills.ts +58 -0
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +103 -0
- package/node_modules/@llblab/pi-state-flow/lib/state.ts +20 -0
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +16 -0
- package/node_modules/@llblab/pi-state-flow/lib/terminal.ts +148 -0
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +47 -0
- package/node_modules/@llblab/pi-state-flow/lib/validation.ts +27 -0
- package/node_modules/@llblab/pi-state-flow/package.json +55 -0
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +3 -0
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +18 -0
- package/node_modules/@llblab/pi-telegram/README.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +5 -3
- package/node_modules/@llblab/pi-telegram/docs/compact-matrix-literal.md +39 -11
- package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +17 -5
- package/node_modules/@llblab/pi-telegram/docs/outbound.md +6 -4
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +1 -1
- package/node_modules/@llblab/pi-telegram/index.ts +13 -1
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +12 -3
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +29 -18
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +15 -6
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +11 -4
- package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +5 -3
- package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +72 -15
- package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +81 -9
- package/node_modules/@llblab/pi-telegram/lib/outbound.ts +2 -0
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +89 -32
- package/node_modules/@llblab/pi-telegram/lib/sync.ts +74 -15
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +32 -1
- package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +17 -0
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +123 -15
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/skills/generated-control-surface/SKILL.md +4 -2
- package/node_modules/@llblab/pi-telegram/skills/generated-control-surface/references/layout-and-state.md +4 -2
- package/node_modules/@llblab/pi-telegram/skills/generative-apps/SKILL.md +4 -3
- package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/SKILL.md +19 -8
- package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/diagnosis.md +4 -2
- package/node_modules/@llblab/skills/abcd-context/AGENTS.md +40 -0
- package/node_modules/@llblab/skills/abcd-context/BACKLOG.md +3 -0
- package/node_modules/@llblab/skills/abcd-context/CHANGELOG.md +19 -0
- package/node_modules/@llblab/skills/abcd-context/README.md +30 -0
- package/node_modules/@llblab/skills/abcd-context/SKILL.md +122 -0
- package/node_modules/@llblab/skills/abcd-context/docs/README.md +9 -0
- package/node_modules/@llblab/skills/abcd-context/docs/protocols.md +199 -0
- package/node_modules/@llblab/skills/abcd-context/docs/templates.md +194 -0
- package/node_modules/@llblab/skills/abcd-context/docs/validation-design.md +117 -0
- package/node_modules/@llblab/skills/abcd-context/fixtures/abcd-project/AGENTS.md +10 -0
- package/node_modules/@llblab/skills/abcd-context/fixtures/abcd-project/BACKLOG.md +5 -0
- package/node_modules/@llblab/skills/abcd-context/fixtures/abcd-project/CHANGELOG.md +5 -0
- package/node_modules/@llblab/skills/abcd-context/fixtures/abcd-project/README.md +10 -0
- package/node_modules/@llblab/skills/abcd-context/fixtures/abcd-project/docs/README.md +7 -0
- package/node_modules/@llblab/skills/abcd-context/fixtures/abcd-project/docs/overview.md +3 -0
- package/node_modules/@llblab/skills/abcd-context/recipes/validate-context.json +7 -0
- package/node_modules/@llblab/skills/abcd-context/scripts/_self-test.mjs +244 -0
- package/node_modules/@llblab/skills/abcd-context/scripts/validate-context.mjs +497 -0
- package/node_modules/@llblab/skills/brain-storm/AGENTS.md +5 -0
- package/node_modules/@llblab/skills/brain-storm/SKILL.md +321 -0
- package/node_modules/@llblab/skills/coding-contract/SKILL.md +228 -0
- package/node_modules/@llblab/skills/domain-dag/AGENTS.md +6 -0
- package/node_modules/@llblab/skills/domain-dag/SKILL.md +257 -0
- package/node_modules/@llblab/skills/domain-dag/domain-dag.json +9 -0
- package/node_modules/@llblab/skills/domain-dag/recipes/validate-domain-dag.json +7 -0
- package/node_modules/@llblab/skills/domain-dag/scripts/validate-domain-dag.mjs +771 -0
- package/node_modules/@llblab/skills/domain-dag/scripts/validate-domain-dag.sh +4 -0
- package/node_modules/@llblab/skills/edge-tts/AGENTS.md +19 -0
- package/node_modules/@llblab/skills/edge-tts/SKILL.md +56 -0
- package/node_modules/@llblab/skills/edge-tts/recipes/say-edge.json +9 -0
- package/node_modules/@llblab/skills/edge-tts/scripts/say.mjs +1548 -0
- package/node_modules/@llblab/skills/edge-tts/scripts/say.sh +4 -0
- package/node_modules/@llblab/skills/extra-self/SKILL.md +229 -0
- package/node_modules/@llblab/skills/frontend-design/SKILL.md +78 -0
- package/node_modules/@llblab/skills/groq-stt/AGENTS.md +15 -0
- package/node_modules/@llblab/skills/groq-stt/SKILL.md +35 -0
- package/node_modules/@llblab/skills/groq-stt/recipes/transcribe-groq.json +10 -0
- package/node_modules/@llblab/skills/groq-stt/scripts/transcribe.mjs +190 -0
- package/node_modules/@llblab/skills/groq-stt/scripts/transcribe.sh +4 -0
- package/node_modules/@llblab/skills/mistral-stt/AGENTS.md +15 -0
- package/node_modules/@llblab/skills/mistral-stt/SKILL.md +35 -0
- package/node_modules/@llblab/skills/mistral-stt/recipes/transcribe-mistral.json +10 -0
- package/node_modules/@llblab/skills/mistral-stt/scripts/transcribe.mjs +191 -0
- package/node_modules/@llblab/skills/mistral-stt/scripts/transcribe.sh +4 -0
- package/node_modules/@llblab/skills/package.json +46 -0
- package/node_modules/@llblab/skills/re-review/SKILL.md +318 -0
- package/node_modules/@llblab/skills/release-flow/SKILL.md +456 -0
- package/node_modules/@llblab/skills/show-me/SKILL.md +144 -0
- package/package.json +20 -8
- package/node_modules/@llblab/pi-actors/dist/skills/music-player/scripts/playback-client.mjs +0 -143
- package/node_modules/@llblab/pi-actors/skills/music-player/scripts/playback-client.mjs +0 -143
package/AGENTS.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Product Contract
|
|
4
4
|
|
|
5
5
|
- `@llblab/pi-kit` is a Pi package distribution, not a Pi extension.
|
|
6
|
-
- It bundles independently released LLBLAB extensions behind one installable package.
|
|
6
|
+
- It bundles independently released LLBLAB extensions and Skill packages behind one installable package.
|
|
7
7
|
- Every included package version is exact. Ranges, floating tags, local paths, and unpublished refs are forbidden in release state.
|
|
8
8
|
- The kit owns composition and version selection only. Runtime behavior, Skills, documentation, and implementation remain owned by the included packages.
|
|
9
9
|
- Loading order is explicit in `package.json`; do not rely on recursive package discovery.
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
- Expose only resources declared by each included package. Prefer published distribution entrypoints over source entrypoints when both exist.
|
|
25
25
|
- Do not copy extension source, Skills, or documentation into this repository.
|
|
26
26
|
- Preserve package independence: a kit release may advance any subset of included extensions without forcing lockstep extension releases.
|
|
27
|
-
-
|
|
27
|
+
- Adding packages or newly exposed capabilities requires a kit minor bump. For updates to the existing composition, derive the kit version bump from the highest dependency bump in the synchronized release cohort: dependency patch-only updates require a kit patch bump, while any dependency minor update requires a kit minor bump. Do not let lower-level dependency bumps force a larger kit bump.
|
|
28
28
|
- Use English for public and repository-facing text.
|
|
29
29
|
- Do not commit, publish, tag, create a remote repository, or mutate Pi settings without explicit authorization.
|
|
30
30
|
|
|
@@ -32,5 +32,5 @@
|
|
|
32
32
|
|
|
33
33
|
- Run `npm test` after manifest or inventory changes.
|
|
34
34
|
- Run `npm run pack:check` before declaring package readiness.
|
|
35
|
-
- Inspect the dry-run tarball inventory to confirm
|
|
35
|
+
- Inspect the dry-run tarball inventory to confirm every package in `bundledDependencies` and its declared resources are present.
|
|
36
36
|
- Run `npm run validate` at completion.
|
package/BACKLOG.md
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@llblab/pi-kit` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.5.0 - 2026-09-05
|
|
6
|
+
|
|
7
|
+
- `Telegram Native Controls`: Advances the exact Telegram pin to `0.43.0`, bringing in-body button blocks, shared JSON/CML disabled controls, HTML footer fallback, and updated agent Skills while preserving package-owned implementations and the existing resource inventory.
|
|
8
|
+
|
|
9
|
+
## 0.4.0 - 2026-09-05
|
|
10
|
+
|
|
11
|
+
- `Expanded Composition`: Adds exact published pins for Clean Room and opt-in State Flow alongside the portable LLBLAB Skills collection, exposing each package's own declared resources without duplicating source or runtime ownership.
|
|
12
|
+
- `Verified Hotfix Cohort`: Advances Actors to `0.52.1`, Grow Loop to `0.7.4`, and Telegram to `0.42.4`, including guarded thread recovery and cleanup, while retaining independent package release ownership.
|
|
13
|
+
- `Independent Package Guide`: Links every included package to its owning repository, explains its purpose, and documents duplicate-resource configuration for users migrating from individual installations.
|
|
14
|
+
|
|
5
15
|
## 0.3.2 - 2026-09-01
|
|
6
16
|
|
|
7
17
|
- `Telegram Comment Membrane`: Advances `@llblab/pi-telegram` to `0.42.2`, keeping assistant-authored HTML comments transport-private across Telegram previews and final replies while preserving top-level button and voice activation and skipping empty text sends after sanitization.
|
package/README.md
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
# @llblab/pi-kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
One install for the LLB Lab extension and Skill collection for [Pi](https://github.com/earendil-works/pi).
|
|
4
|
+
|
|
5
|
+
`@llblab/pi-kit` is a version-pinned package distribution, not another runtime extension. It brings together independently maintained packages; each keeps its own repository, releases, documentation, and development lifecycle.
|
|
4
6
|
|
|
5
7
|
## Included packages
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Package links lead to the owning repositories for usage, documentation, issues, and contributions.
|
|
10
|
+
|
|
11
|
+
| Package | Version | Purpose |
|
|
8
12
|
| --- | ---: | --- |
|
|
9
|
-
| `@llblab/pi-actors` | `0.52.
|
|
10
|
-
| `@llblab/pi-
|
|
11
|
-
| `@llblab/pi-
|
|
12
|
-
| `@llblab/pi-
|
|
13
|
+
| [`@llblab/pi-actors`](https://github.com/llblab/pi-actors) | `0.52.1` | Inspectable local Runs, reusable Recipes, persistent tools, and delegation Skills |
|
|
14
|
+
| [`@llblab/pi-clean-room`](https://github.com/llblab/pi-clean-room) | `0.1.1` | Isolated nested Pi TUI with explicitly selected extensions |
|
|
15
|
+
| [`@llblab/pi-codex-usage`](https://github.com/llblab/pi-codex-usage) | `0.9.4` | Compact Codex/Spark subscription-limit status |
|
|
16
|
+
| [`@llblab/pi-grow-loop`](https://github.com/llblab/pi-grow-loop) | `0.7.4` | Visible continuation scheduling and bounded worker Skills |
|
|
17
|
+
| [`@llblab/pi-state-flow`](https://github.com/llblab/pi-state-flow) | `0.3.0` | Opt-in validated state handoffs between agent runs |
|
|
18
|
+
| [`@llblab/pi-telegram`](https://github.com/llblab/pi-telegram) | `0.43.0` | Telegram companion, queues, files, voice, controls, and Generative Apps guidance |
|
|
19
|
+
| [`@llblab/skills`](https://github.com/llblab/skills) | `1.14.0` | Portable workflows for engineering, review, design, context maintenance, and other focused tasks |
|
|
13
20
|
|
|
14
|
-
Versions are exact by design.
|
|
21
|
+
Versions are exact by design. An upstream release does not change an installed kit until this repository explicitly advances the dependency and publishes a new kit version. Runtime defects and package-specific feature requests belong in the linked repository; package selection and kit installation issues belong here.
|
|
15
22
|
|
|
16
23
|
## Install
|
|
17
24
|
|
|
@@ -27,7 +34,9 @@ From GitHub:
|
|
|
27
34
|
pi install git:github.com/llblab/pi-kit
|
|
28
35
|
```
|
|
29
36
|
|
|
30
|
-
Pi loads the
|
|
37
|
+
Pi loads the six extension entrypoints and the Skill resources explicitly declared by the kit. The kit adds no runtime behavior and does not copy the packages' source or instructions into a new owner. State Flow remains opt-in; bundling it does not enable its state handoff mode.
|
|
38
|
+
|
|
39
|
+
Prefer the kit instead of separately loading the same packages. If you already use individual installations or local Skill copies, use `pi config` to disable duplicate resources. Installing the kit does not remove or rewrite those installations.
|
|
31
40
|
|
|
32
41
|
## Development
|
|
33
42
|
|
|
@@ -36,8 +45,8 @@ npm install
|
|
|
36
45
|
npm run validate
|
|
37
46
|
```
|
|
38
47
|
|
|
39
|
-
To advance
|
|
48
|
+
To advance an included package, update its exact version in `dependencies`, run `npm install`, synchronize bundled dependencies, declared resource paths, tests, the table above, and the changelog, then validate the packed artifact. Expose only resources declared by the published owning package; do not use version ranges or unpublished local paths.
|
|
40
49
|
|
|
41
50
|
## Security
|
|
42
51
|
|
|
43
|
-
Pi extensions execute with the user's system permissions. Review
|
|
52
|
+
Pi extensions execute with the user's system permissions, and Skills can guide executable actions. Review each included package and release before advancing its pin. Private Knowledge, credentials, and personal Pi configuration are not bundled.
|
|
@@ -144,6 +144,7 @@ When deferred Run results gate the next step, wait for their completion batch. I
|
|
|
144
144
|
|
|
145
145
|
- Keep published text portable: use `~`, `<repo>`, or relative paths.
|
|
146
146
|
- Update `skills/actors/SKILL.md` when durable operating mechanics change.
|
|
147
|
+
- For registration or agent-instruction changes, use `tests/registration-truth.test.ts` for resolution/admission/activation truth and `tests/agent-journeys.test.ts` for public agent journeys, then check installed-package parity at the affected boundary. Fresh-agent operating evidence must use the active Skills and public tools rather than repository source or copied helper contracts.
|
|
147
148
|
- Keep `skills/swarm/SKILL.md` focused on multi-agent methodology rather than kernel internals.
|
|
148
149
|
- Recipe `description` is optional. Skill Recipe QA recursively validates direct filesystem-owned components and capability semantics with zero diagnostics or warnings; it does not enforce aesthetics or architecture policy.
|
|
149
150
|
- Before release run the normal product validation and dependency audit. Use the project-local Domain DAG Skill during architecture-affecting development, not as publication automation.
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
> Each release keeps at most 8 outcome records of at most 512 characters.
|
|
4
4
|
|
|
5
|
+
## 0.52.1: Unified Playback Control Hotfix
|
|
6
|
+
|
|
7
|
+
- `Unified Playback CLI`: Consolidates standalone playback and external control into `playback.mjs`; standalone commands remain runtime-independent, while Actor-owned commands retain exact terminal Control evidence. The maintained Music Player Generative App uses the same explicit control entrypoint. Post-stop status remains readable despite leftover Run metadata; inactive controls fail before journal admission. External callers of the removed `playback-client.mjs` use `playback.mjs control` instead.
|
|
8
|
+
- `Skill Ownership`: Keeps extension operation and the capability/Recipe map in Actors, multi-participant coordination and quorum in Swarm, and development detail in focused references. Preserves registration/agent-journey evidence routing in AGENTS while removing obsolete delivery Skills, historical evidence reports, and tests coupled only to that retired prose.
|
|
9
|
+
- `Local Architecture Tooling`: Restores the project-local Domain DAG Skill's portable, configurable graph validator and focused maintenance contract, replacing repository-specific defaults and removing its obsolete Recipe/config wrappers. Architecture tooling remains agent-owned and outside npm publication and CI gates.
|
|
10
|
+
|
|
5
11
|
## 0.52.0: Durable Coordinator Delivery
|
|
6
12
|
|
|
7
13
|
- `Completion Epochs`: Replaces per-Run terminal turns with one immutable owner-fenced completion batch per idle/settled epoch. Batches retain exact Run generations and terminal timestamps, bound durable and model-facing members, preserve silent and synchronous-stop semantics, and remain eligible after urgent steering.
|
|
@@ -76,16 +76,26 @@ Then:
|
|
|
76
76
|
|
|
77
77
|
Use direct delegation for the same maintained capability under a persistent name or narrower defaults. Use named imports only when one Recipe graph contains reusable child nodes. See [persistent tools](./references/persistent-tools.md) and [Recipes](./references/recipes.md).
|
|
78
78
|
|
|
79
|
-
##
|
|
79
|
+
## Capability map
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
Recipes remain with the Skill that owns their behavior. Load that Skill for selection and caller inputs; this map is routing, not a copied Recipe contract.
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
| Owner | Recipe families |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `actors` | `command-validate`, `recipe-validate`, `jsonl-tail`, `run-summary`, `run-state-files`, `run-ops-snapshot`, `resource-locker`, `resource-locker-snapshot` |
|
|
86
|
+
| `swarm` | Lens and quorum reviews, research synthesis, architecture, development tasking, readiness, and supporting `subagent-*` components |
|
|
87
|
+
| `artifacts` | Report, write, manifest, bundle, and supporting file-write |
|
|
88
|
+
| `project-work` | Repository health, docs maintenance, release readiness/summary, Run reports, and supporting deterministic snapshots |
|
|
89
|
+
| `music-player` | The controlled `playback` singleton |
|
|
90
|
+
| `recipe-memory` | Internal automatic reviewers; use its Skill only for diagnosis/recovery |
|
|
85
91
|
|
|
86
|
-
|
|
92
|
+
Use the `actors/*` helpers only for their narrow requested result or intentional composition. Prefer public `inspect` for ordinary runtime diagnosis and the capability's primary workflow for a complete outcome.
|
|
87
93
|
|
|
88
|
-
Delegation
|
|
94
|
+
## Delegation boundary
|
|
95
|
+
|
|
96
|
+
The current Pi instance owns user authority and the final result; pi-actors creates explicit local Runs, while companion transports provide presence rather than hidden instance creation. Keep short single-boundary work inline when delegation adds no value. For several participants, reasoning allocation, quorum, or integration methodology, read `swarm`.
|
|
97
|
+
|
|
98
|
+
Treat `attention: "steer"` as an actor-authored urgent semantic checkpoint at Pi's next safe boundary, never as a status-derived completion signal; the later root terminal still arrives through its ordinary completion batch.
|
|
89
99
|
|
|
90
100
|
## Run workflow
|
|
91
101
|
|
|
@@ -13,7 +13,7 @@ When a Telegram-originated turn or explicit Telegram-control question makes repe
|
|
|
13
13
|
|
|
14
14
|
## Playback
|
|
15
15
|
|
|
16
|
-
`music-player/playback` is a singleton async controlled service with the canonical address `run:music-player`. The Recipe is the sole lifecycle owner: it starts the service, supervises it, and stops playback when the Run closes. The service owns queue, backend, checkpoint, and playback state. `playback
|
|
16
|
+
`music-player/playback` is a singleton async controlled service with the canonical address `run:music-player`. The Recipe is the sole lifecycle owner: it starts the service, supervises it, and stops playback when the Run closes. The service owns queue, backend, checkpoint, and playback state. `scripts/playback.mjs` owns both foreground playback and the bounded control CLI. Its `control <state-dir> <action> [percent]` entrypoint observes or controls an existing owner without starting, adopting, or supervising it. Explicit foreground `serve` supports a caller-owned standalone host without importing the Actor runtime; Actor and standalone ownership of one state directory are mutually exclusive.
|
|
17
17
|
|
|
18
18
|
```text
|
|
19
19
|
spawn recipe=music-player/playback values={"source":"~/Music","player":"auto"}
|
|
@@ -35,14 +35,14 @@ Use only declared actions: `play`, `pause`, `resume`, `toggle`, `next`, `previou
|
|
|
35
35
|
- `status` is read-only and exposes bounded machine-readable player state, including the current absolute volume and a duration-derived progress percentage projected at read time.
|
|
36
36
|
- `stop` ends the live process without silently deleting the saved queue.
|
|
37
37
|
|
|
38
|
-
External local views use
|
|
38
|
+
External local views use `playback.mjs control <state-dir> <action> [percent]`. For Actor-owned playback, the script validates Run availability, queues canonical Control, and waits for that exact record to become handled or failed. For standalone playback, it sends a bounded generation-fenced command to the service endpoint without creating Run, Control, or Trace state. Views themselves never read or edit Run files, signal processes, construct Control records, or import pi-actors internals. `status` is read-only and reports `actor_available` separately from playback state.
|
|
39
39
|
|
|
40
40
|
## Maintained Telegram View
|
|
41
41
|
|
|
42
42
|
> [!NOTE]
|
|
43
43
|
> This Skill includes a ready Music Player Generative App at `genapps/music-player.mjs`. When `telegram_bind` is available and Telegram interaction is relevant, use it to copy and install the app as `music-player`; hot replacement keeps the same app name with `replace: true`.
|
|
44
44
|
|
|
45
|
-
Bind with absolute `control
|
|
45
|
+
Bind with absolute `control` (the `scripts/playback.mjs` path), `stateDir`, and `node` arguments. This maintained adapter targets Actor-owned playback and uses the unified `control` entrypoint above for status and mutation; it displays controls only when `actor_available` is true. Exact terminal Control evidence remains visible in the Run inspector and failures reach Telegram. The adapter neither imports extension internals nor starts playback. Its stopped-state Start button returns to Pi so the composition root can spawn `music-player/playback`, while active controls remain deterministic Generative App actions that bypass the model. `pi-telegram` owns only the generic Generative App runtime.
|
|
46
46
|
|
|
47
47
|
## Sources And Backends
|
|
48
48
|
|
|
@@ -70,7 +70,7 @@ function normalizePlayback(status) {
|
|
|
70
70
|
async function readPlayback(adapter, run) {
|
|
71
71
|
const result = await run({
|
|
72
72
|
command: adapter.node,
|
|
73
|
-
args: [adapter.control, "
|
|
73
|
+
args: [adapter.control, "control", adapter.stateDir, "status"],
|
|
74
74
|
cwd: dirname(adapter.control),
|
|
75
75
|
timeoutMs: 5_000,
|
|
76
76
|
});
|
|
@@ -188,8 +188,9 @@ async function applyVolume(percent, context) {
|
|
|
188
188
|
command: context.state.adapter.node,
|
|
189
189
|
args: [
|
|
190
190
|
context.state.adapter.control,
|
|
191
|
-
"
|
|
191
|
+
"control",
|
|
192
192
|
context.state.adapter.stateDir,
|
|
193
|
+
"volume",
|
|
193
194
|
String(percent),
|
|
194
195
|
],
|
|
195
196
|
cwd: dirname(context.state.adapter.control),
|
|
@@ -224,8 +225,9 @@ async function applySeek(percent, context) {
|
|
|
224
225
|
command: context.state.adapter.node,
|
|
225
226
|
args: [
|
|
226
227
|
context.state.adapter.control,
|
|
227
|
-
"
|
|
228
|
+
"control",
|
|
228
229
|
context.state.adapter.stateDir,
|
|
230
|
+
"seek",
|
|
229
231
|
String(percent),
|
|
230
232
|
],
|
|
231
233
|
cwd: dirname(context.state.adapter.control),
|
|
@@ -253,7 +255,7 @@ async function apply(action, context) {
|
|
|
253
255
|
const before = await readPlayback(context.state.adapter, context.run);
|
|
254
256
|
const result = await context.run({
|
|
255
257
|
command: context.state.adapter.node,
|
|
256
|
-
args: [context.state.adapter.control,
|
|
258
|
+
args: [context.state.adapter.control, "control", context.state.adapter.stateDir, action],
|
|
257
259
|
cwd: dirname(context.state.adapter.control),
|
|
258
260
|
timeoutMs: 5_000,
|
|
259
261
|
});
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
watch,
|
|
28
28
|
writeFileSync,
|
|
29
29
|
} from "node:fs";
|
|
30
|
-
import { createServer } from "node:net";
|
|
30
|
+
import { createConnection, createServer } from "node:net";
|
|
31
31
|
import { homedir } from "node:os";
|
|
32
32
|
import {
|
|
33
33
|
basename,
|
|
@@ -66,7 +66,7 @@ let updateRunControlStatusInStateDir;
|
|
|
66
66
|
let isAlive;
|
|
67
67
|
let verifyRunProcessIdentity;
|
|
68
68
|
let appendRunTraceEvent = () => {};
|
|
69
|
-
|
|
69
|
+
async function loadActorAdapter() {
|
|
70
70
|
({
|
|
71
71
|
appendRunControlInStateDir,
|
|
72
72
|
claimRunControlByIdInStateDir,
|
|
@@ -110,8 +110,9 @@ function usage() {
|
|
|
110
110
|
playback.mjs control <state-dir> <play|pause|toggle|next|previous|seek|volume|stop|status> [percent]
|
|
111
111
|
|
|
112
112
|
Runs a foreground music player so pi-actors can own it as a controlled Run.
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
Actor-owned controls use canonical records in <state-dir>/controls.jsonl.
|
|
114
|
+
Standalone controls use the generation-fenced playback service endpoint.
|
|
115
|
+
Prefer message target=run:<run> action=<command> for Actors; external adapters use control <state-dir> <action>.
|
|
115
116
|
Supported players: auto, mpv, afplay, ffplay, cvlc, play, wmp.
|
|
116
117
|
`);
|
|
117
118
|
}
|
|
@@ -1134,6 +1135,7 @@ function readAndClearCommand(ctx) {
|
|
|
1134
1135
|
}
|
|
1135
1136
|
|
|
1136
1137
|
async function playMain(args) {
|
|
1138
|
+
if (actorAdapterEnabled) await loadActorAdapter();
|
|
1137
1139
|
const [
|
|
1138
1140
|
sourceArg,
|
|
1139
1141
|
loopArg = "true",
|
|
@@ -1333,30 +1335,74 @@ function projectCurrentProgress(status, nowMs = Date.now()) {
|
|
|
1333
1335
|
};
|
|
1334
1336
|
}
|
|
1335
1337
|
|
|
1336
|
-
function actorControlAvailability(stateDir) {
|
|
1338
|
+
async function actorControlAvailability(stateDir) {
|
|
1337
1339
|
const run = readJsonFile(join(stateDir, "run.json"), {});
|
|
1338
1340
|
const result = readJsonFile(join(stateDir, "result.json"), {});
|
|
1339
1341
|
const endpoint = readJsonFile(join(stateDir, "control-endpoint.json"), {});
|
|
1340
1342
|
const playerStatus = readJsonFile(join(stateDir, "player.json"), {});
|
|
1343
|
+
const runInstanceId = typeof run.run_instance_id === "string"
|
|
1344
|
+
? run.run_instance_id
|
|
1345
|
+
: undefined;
|
|
1346
|
+
// Inactive status must remain readable without an installed Actor runtime,
|
|
1347
|
+
// including standalone state beside metadata from a rejected Actor launch.
|
|
1348
|
+
if (!runInstanceId || typeof result.completedAt === "string" ||
|
|
1349
|
+
endpoint.run_instance_id !== runInstanceId ||
|
|
1350
|
+
!["playing", "paused"].includes(playerStatus.state)) {
|
|
1351
|
+
return { available: false, runInstanceId };
|
|
1352
|
+
}
|
|
1353
|
+
if (!verifyRunProcessIdentity) {
|
|
1354
|
+
await loadActorAdapter();
|
|
1355
|
+
// Re-read authority after the asynchronous import before admitting control.
|
|
1356
|
+
return actorControlAvailability(stateDir);
|
|
1357
|
+
}
|
|
1341
1358
|
const pid = Number(run.pid || 0);
|
|
1342
1359
|
const hasProcessIdentity = pid > 0 || run.process_identity !== undefined;
|
|
1343
1360
|
const processIdentity = pid > 0
|
|
1344
1361
|
? verifyRunProcessIdentity(pid, run.process_identity)
|
|
1345
1362
|
: { valid: false };
|
|
1346
|
-
const available =
|
|
1347
|
-
typeof run.run_instance_id === "string" &&
|
|
1348
|
-
typeof result.completedAt !== "string" &&
|
|
1349
|
-
(!hasProcessIdentity || (pid > 0 && isAlive(pid) && processIdentity.valid === true)) &&
|
|
1350
|
-
endpoint.run_instance_id === run.run_instance_id &&
|
|
1351
|
-
["playing", "paused"].includes(playerStatus.state);
|
|
1352
1363
|
return {
|
|
1353
|
-
available
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
: undefined,
|
|
1364
|
+
available: !hasProcessIdentity ||
|
|
1365
|
+
(pid > 0 && isAlive(pid) && processIdentity.valid === true),
|
|
1366
|
+
runInstanceId,
|
|
1357
1367
|
};
|
|
1358
1368
|
}
|
|
1359
1369
|
|
|
1370
|
+
async function sendPlaybackCommand(endpoint, action, input) {
|
|
1371
|
+
const payload = `${JSON.stringify({
|
|
1372
|
+
action,
|
|
1373
|
+
...(input !== undefined ? { input } : {}),
|
|
1374
|
+
service_instance_id: endpoint.service_instance_id,
|
|
1375
|
+
})}\n`;
|
|
1376
|
+
const response = await new Promise((resolveResponse, rejectResponse) => {
|
|
1377
|
+
const socket = createConnection(endpoint.path);
|
|
1378
|
+
let content = "";
|
|
1379
|
+
const timeout = setTimeout(() => {
|
|
1380
|
+
socket.destroy(new Error("playback service command timed out"));
|
|
1381
|
+
}, 5_000);
|
|
1382
|
+
timeout.unref?.();
|
|
1383
|
+
socket.setEncoding("utf8");
|
|
1384
|
+
socket.on("connect", () => socket.write(payload));
|
|
1385
|
+
socket.on("data", (chunk) => {
|
|
1386
|
+
content += chunk;
|
|
1387
|
+
if (Buffer.byteLength(content, "utf8") > 4096) {
|
|
1388
|
+
socket.destroy(new Error("playback service response is too large"));
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
socket.on("close", () => clearTimeout(timeout));
|
|
1392
|
+
socket.on("error", rejectResponse);
|
|
1393
|
+
socket.on("end", () => {
|
|
1394
|
+
try {
|
|
1395
|
+
resolveResponse(JSON.parse(content.trim()));
|
|
1396
|
+
} catch {
|
|
1397
|
+
rejectResponse(new Error("playback service returned invalid JSON"));
|
|
1398
|
+
}
|
|
1399
|
+
});
|
|
1400
|
+
});
|
|
1401
|
+
if (response?.ok !== true) {
|
|
1402
|
+
throw new Error(response?.error || "playback service rejected the command");
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1360
1406
|
async function controlMain(args) {
|
|
1361
1407
|
const stateDir = expandPath(args[0] || "");
|
|
1362
1408
|
const command = args[1] || "status";
|
|
@@ -1365,13 +1411,20 @@ async function controlMain(args) {
|
|
|
1365
1411
|
usage();
|
|
1366
1412
|
process.exit(2);
|
|
1367
1413
|
}
|
|
1368
|
-
|
|
1414
|
+
if (!CONTROL_COMMANDS.has(command)) fail(`unsupported command: ${command}`, 2);
|
|
1415
|
+
const endpoint = readJsonFile(join(stateDir, "playback-endpoint.json"), {});
|
|
1416
|
+
// A standalone service retains authority even if an unsuccessful Actor launch
|
|
1417
|
+
// left Run metadata beside its endpoint. Clients never start or adopt it.
|
|
1418
|
+
const actorOwned = endpoint.owner_mode !== "standalone" &&
|
|
1419
|
+
existsSync(join(stateDir, "run.json"));
|
|
1369
1420
|
if (command === "status") {
|
|
1370
1421
|
const statusFile = join(stateDir, "player.json");
|
|
1371
1422
|
const status = exists(statusFile)
|
|
1372
1423
|
? readJsonFile(statusFile, { state: "unknown" })
|
|
1373
1424
|
: { state: "unknown" };
|
|
1374
|
-
const actor =
|
|
1425
|
+
const actor = actorOwned
|
|
1426
|
+
? await actorControlAvailability(stateDir)
|
|
1427
|
+
: { available: false };
|
|
1375
1428
|
process.stdout.write(`${JSON.stringify({
|
|
1376
1429
|
...projectCurrentProgress(status),
|
|
1377
1430
|
actor_available: actor.available,
|
|
@@ -1381,7 +1434,7 @@ async function controlMain(args) {
|
|
|
1381
1434
|
})}\n`);
|
|
1382
1435
|
return;
|
|
1383
1436
|
}
|
|
1384
|
-
if (!actorControlAvailability(stateDir).available) {
|
|
1437
|
+
if (actorOwned && !(await actorControlAvailability(stateDir)).available) {
|
|
1385
1438
|
fail(`Run playback is not active: ${stateDir}`, 3);
|
|
1386
1439
|
}
|
|
1387
1440
|
let input;
|
|
@@ -1396,6 +1449,20 @@ async function controlMain(args) {
|
|
|
1396
1449
|
fail(error instanceof Error ? error.message : String(error), 2);
|
|
1397
1450
|
}
|
|
1398
1451
|
}
|
|
1452
|
+
if (!actorOwned) {
|
|
1453
|
+
if (endpoint.owner_mode !== "standalone" ||
|
|
1454
|
+
typeof endpoint.path !== "string" || !endpoint.path ||
|
|
1455
|
+
typeof endpoint.service_instance_id !== "string" || !endpoint.service_instance_id) {
|
|
1456
|
+
fail(`standalone playback service is not active: ${stateDir}`, 3);
|
|
1457
|
+
}
|
|
1458
|
+
try {
|
|
1459
|
+
await sendPlaybackCommand(endpoint, command === "resume" ? "play" : command, input);
|
|
1460
|
+
console.log(`music-player: command=${command} handled state_dir=${stateDir}`);
|
|
1461
|
+
return;
|
|
1462
|
+
} catch (error) {
|
|
1463
|
+
fail(error instanceof Error ? error.message : String(error), 3);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1399
1466
|
const queued = appendControl(
|
|
1400
1467
|
{ controlsFile: join(stateDir, "controls.jsonl"), stateDir },
|
|
1401
1468
|
command,
|
|
@@ -9,13 +9,9 @@ Use multi-actor execution only when at least two scopes or evidence lenses are m
|
|
|
9
9
|
|
|
10
10
|
Read `actors` first for generic Recipe, spawn, Run, Trace, Control, artifact, and lifecycle operation. This Skill owns only multi-actor methodology: decomposition, scope ownership, independence, synthesis, integration, and completion proof.
|
|
11
11
|
|
|
12
|
-
## Coordinator
|
|
12
|
+
## Coordinator and participants
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
This resembles gateway orchestration in dependency direction but not in ownership: the coordinator is itself an agent instance with inspectable Runs, not an infrastructure service that implicitly creates sessions. Preserve that distinction in prompts, docs, recovery, and target routing.
|
|
17
|
-
|
|
18
|
-
Once work is delegated, keep the coordinator available for decisions and integration instead of duplicating participant implementation. Wait for the settled completion batch by default; use meaningful attention or evidence-based timers for overdue work rather than a tight inspection loop.
|
|
14
|
+
The coordinator owns decomposition, shared contracts, integration order, and final validation. Participants own bounded tasks or evidence lenses. Keep the coordinator available for decisions instead of duplicating participant implementation; use `actors` for launch, observation, and lifecycle mechanics.
|
|
19
15
|
|
|
20
16
|
## Reasoning allocation
|
|
21
17
|
|
|
@@ -14,38 +14,9 @@ Use a development swarm only when all are true:
|
|
|
14
14
|
|
|
15
15
|
Do not parallelize implementation when tasks need the same central files, semantic ordering dominates wall-clock time, or the likely conflicts would invalidate the decomposition. Use planning or review first.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Roles and reasoning
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
The coordinator should:
|
|
22
|
-
|
|
23
|
-
- Translate high-level intent into bounded task cards and dependency edges.
|
|
24
|
-
- Keep user authority, shared contracts, integration order, and final validation local.
|
|
25
|
-
- Remain available for checkpoints, permissions, conflicts, and changing evidence.
|
|
26
|
-
- Consume terminal handoffs, durable artifacts, and Trace attention instead of mirroring participant work.
|
|
27
|
-
- Check overdue work on an evidence-based timer; never replace event-driven completion with a rapid polling loop.
|
|
28
|
-
|
|
29
|
-
A participant should:
|
|
30
|
-
|
|
31
|
-
- Own one concrete execution or evidence boundary.
|
|
32
|
-
- Avoid global orchestration and undeclared participant creation.
|
|
33
|
-
- Return a bounded handoff that lets the coordinator decide without replaying the entire task.
|
|
34
|
-
|
|
35
|
-
Use one ordinary Run under `actors` when only one worker is delegated. Activate this development-swarm protocol when two or more participants, parallel ownership, or explicit integration edges exist. Keep trivial single-boundary work inline when delegation overhead has no compensating value.
|
|
36
|
-
|
|
37
|
-
## Reasoning profiles
|
|
38
|
-
|
|
39
|
-
| Role | Default | Raise or fan out when |
|
|
40
|
-
| --- | --- | --- |
|
|
41
|
-
| Bounded implementation author | Reasoning off | The card explicitly owns unresolved diagnosis or design judgement |
|
|
42
|
-
| Reviewer | Medium reasoning, clean context | Stakes require independent lenses or repeated judges |
|
|
43
|
-
| Synthesizer / integrator | Medium reasoning | Evidence conflicts, shared contracts move, or merge order is semantic |
|
|
44
|
-
| Coordinator | Sufficient for decomposition and decisions | Scope, authority, or architecture remains unresolved |
|
|
45
|
-
|
|
46
|
-
Prefer independent review after implementation over asking one author thread to implement, retain all local assumptions, and then certify itself. When risk justifies the cost, use multiple independent reviewers: different lenses increase breadth, while repeated judges increase confidence. Preserve minority high-impact findings and merge only evidence-backed conclusions.
|
|
47
|
-
|
|
48
|
-
More reviewers are not automatically better. Do not fan out when they would inspect unstable code, share contaminated context, repeat one unsupported claim, or exceed the value of the decision. Never change an already-running participant solely to enforce a newer profile; add a fresh review boundary if evidence remains open.
|
|
19
|
+
Apply [Swarm's coordinator and reasoning contract](../SKILL.md#reasoning-allocation). Task cards record those profiles and the owned execution boundary; participants return evidence without undeclared orchestration. Do not fan out review over unstable code or contaminated context. The sections below specify development-only task cards, ownership transfers, conflict reports, and integration.
|
|
49
20
|
|
|
50
21
|
## Decompose by ownership
|
|
51
22
|
|
|
@@ -36,7 +36,7 @@ Artifact pipelines terminate in files/manifests and result evidence; they do not
|
|
|
36
36
|
|
|
37
37
|
### Music playback and controlled services
|
|
38
38
|
|
|
39
|
-
- `music-player/playback` — singleton playback service that resolves files, directories, URLs, explicit lists, and playlist files into one persistent queue; it exposes declared playback Controls including arbitrary absolute `volume` percentages, generation-fenced endpoint readiness, structured status, a player-owned continuity checkpoint, and playback Trace. Player selection is `player:enum(auto,mpv,afplay,ffplay,cvlc,play,wmp)=auto`.
|
|
39
|
+
- `music-player/playback` — singleton playback service that resolves files, directories, URLs, explicit lists, and playlist files into one persistent queue; it exposes declared playback Controls including arbitrary absolute `volume` percentages, generation-fenced endpoint readiness, structured status, a player-owned continuity checkpoint, and playback Trace. Player selection is `player:enum(auto,mpv,afplay,ffplay,cvlc,play,wmp)=auto`. The single `skills/music-player/scripts/playback.mjs` executable also supports standalone foreground `serve` and `control <state-dir> <action> [percent]`; control observes the existing owner, using canonical Control records for Actors and generation-fenced RPC for standalone playback. The maintained Generative App uses that same control entrypoint for Actor-owned playback.
|
|
40
40
|
- `actors/resource-locker` — optional queue/lease-lock service with explicit owner/resource input, lock Trace, and a 512-record/1 MiB atomically retained journal.
|
|
41
41
|
|
|
42
42
|
These Recipes declare actor-local Control. Ordinary one-shot Recipes omit it. Helper-backed Skill Recipes self-locate through runtime-owned `{skill_dir}`; callers do not pass package installation roots.
|
|
@@ -76,16 +76,26 @@ Then:
|
|
|
76
76
|
|
|
77
77
|
Use direct delegation for the same maintained capability under a persistent name or narrower defaults. Use named imports only when one Recipe graph contains reusable child nodes. See [persistent tools](./references/persistent-tools.md) and [Recipes](./references/recipes.md).
|
|
78
78
|
|
|
79
|
-
##
|
|
79
|
+
## Capability map
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
Recipes remain with the Skill that owns their behavior. Load that Skill for selection and caller inputs; this map is routing, not a copied Recipe contract.
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
| Owner | Recipe families |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `actors` | `command-validate`, `recipe-validate`, `jsonl-tail`, `run-summary`, `run-state-files`, `run-ops-snapshot`, `resource-locker`, `resource-locker-snapshot` |
|
|
86
|
+
| `swarm` | Lens and quorum reviews, research synthesis, architecture, development tasking, readiness, and supporting `subagent-*` components |
|
|
87
|
+
| `artifacts` | Report, write, manifest, bundle, and supporting file-write |
|
|
88
|
+
| `project-work` | Repository health, docs maintenance, release readiness/summary, Run reports, and supporting deterministic snapshots |
|
|
89
|
+
| `music-player` | The controlled `playback` singleton |
|
|
90
|
+
| `recipe-memory` | Internal automatic reviewers; use its Skill only for diagnosis/recovery |
|
|
85
91
|
|
|
86
|
-
|
|
92
|
+
Use the `actors/*` helpers only for their narrow requested result or intentional composition. Prefer public `inspect` for ordinary runtime diagnosis and the capability's primary workflow for a complete outcome.
|
|
87
93
|
|
|
88
|
-
Delegation
|
|
94
|
+
## Delegation boundary
|
|
95
|
+
|
|
96
|
+
The current Pi instance owns user authority and the final result; pi-actors creates explicit local Runs, while companion transports provide presence rather than hidden instance creation. Keep short single-boundary work inline when delegation adds no value. For several participants, reasoning allocation, quorum, or integration methodology, read `swarm`.
|
|
97
|
+
|
|
98
|
+
Treat `attention: "steer"` as an actor-authored urgent semantic checkpoint at Pi's next safe boundary, never as a status-derived completion signal; the later root terminal still arrives through its ordinary completion batch.
|
|
89
99
|
|
|
90
100
|
## Run workflow
|
|
91
101
|
|
|
@@ -13,7 +13,7 @@ When a Telegram-originated turn or explicit Telegram-control question makes repe
|
|
|
13
13
|
|
|
14
14
|
## Playback
|
|
15
15
|
|
|
16
|
-
`music-player/playback` is a singleton async controlled service with the canonical address `run:music-player`. The Recipe is the sole lifecycle owner: it starts the service, supervises it, and stops playback when the Run closes. The service owns queue, backend, checkpoint, and playback state. `playback
|
|
16
|
+
`music-player/playback` is a singleton async controlled service with the canonical address `run:music-player`. The Recipe is the sole lifecycle owner: it starts the service, supervises it, and stops playback when the Run closes. The service owns queue, backend, checkpoint, and playback state. `scripts/playback.mjs` owns both foreground playback and the bounded control CLI. Its `control <state-dir> <action> [percent]` entrypoint observes or controls an existing owner without starting, adopting, or supervising it. Explicit foreground `serve` supports a caller-owned standalone host without importing the Actor runtime; Actor and standalone ownership of one state directory are mutually exclusive.
|
|
17
17
|
|
|
18
18
|
```text
|
|
19
19
|
spawn recipe=music-player/playback values={"source":"~/Music","player":"auto"}
|
|
@@ -35,14 +35,14 @@ Use only declared actions: `play`, `pause`, `resume`, `toggle`, `next`, `previou
|
|
|
35
35
|
- `status` is read-only and exposes bounded machine-readable player state, including the current absolute volume and a duration-derived progress percentage projected at read time.
|
|
36
36
|
- `stop` ends the live process without silently deleting the saved queue.
|
|
37
37
|
|
|
38
|
-
External local views use
|
|
38
|
+
External local views use `playback.mjs control <state-dir> <action> [percent]`. For Actor-owned playback, the script validates Run availability, queues canonical Control, and waits for that exact record to become handled or failed. For standalone playback, it sends a bounded generation-fenced command to the service endpoint without creating Run, Control, or Trace state. Views themselves never read or edit Run files, signal processes, construct Control records, or import pi-actors internals. `status` is read-only and reports `actor_available` separately from playback state.
|
|
39
39
|
|
|
40
40
|
## Maintained Telegram View
|
|
41
41
|
|
|
42
42
|
> [!NOTE]
|
|
43
43
|
> This Skill includes a ready Music Player Generative App at `genapps/music-player.mjs`. When `telegram_bind` is available and Telegram interaction is relevant, use it to copy and install the app as `music-player`; hot replacement keeps the same app name with `replace: true`.
|
|
44
44
|
|
|
45
|
-
Bind with absolute `control
|
|
45
|
+
Bind with absolute `control` (the `scripts/playback.mjs` path), `stateDir`, and `node` arguments. This maintained adapter targets Actor-owned playback and uses the unified `control` entrypoint above for status and mutation; it displays controls only when `actor_available` is true. Exact terminal Control evidence remains visible in the Run inspector and failures reach Telegram. The adapter neither imports extension internals nor starts playback. Its stopped-state Start button returns to Pi so the composition root can spawn `music-player/playback`, while active controls remain deterministic Generative App actions that bypass the model. `pi-telegram` owns only the generic Generative App runtime.
|
|
46
46
|
|
|
47
47
|
## Sources And Backends
|
|
48
48
|
|
|
@@ -70,7 +70,7 @@ function normalizePlayback(status) {
|
|
|
70
70
|
async function readPlayback(adapter, run) {
|
|
71
71
|
const result = await run({
|
|
72
72
|
command: adapter.node,
|
|
73
|
-
args: [adapter.control, "
|
|
73
|
+
args: [adapter.control, "control", adapter.stateDir, "status"],
|
|
74
74
|
cwd: dirname(adapter.control),
|
|
75
75
|
timeoutMs: 5_000,
|
|
76
76
|
});
|
|
@@ -188,8 +188,9 @@ async function applyVolume(percent, context) {
|
|
|
188
188
|
command: context.state.adapter.node,
|
|
189
189
|
args: [
|
|
190
190
|
context.state.adapter.control,
|
|
191
|
-
"
|
|
191
|
+
"control",
|
|
192
192
|
context.state.adapter.stateDir,
|
|
193
|
+
"volume",
|
|
193
194
|
String(percent),
|
|
194
195
|
],
|
|
195
196
|
cwd: dirname(context.state.adapter.control),
|
|
@@ -224,8 +225,9 @@ async function applySeek(percent, context) {
|
|
|
224
225
|
command: context.state.adapter.node,
|
|
225
226
|
args: [
|
|
226
227
|
context.state.adapter.control,
|
|
227
|
-
"
|
|
228
|
+
"control",
|
|
228
229
|
context.state.adapter.stateDir,
|
|
230
|
+
"seek",
|
|
229
231
|
String(percent),
|
|
230
232
|
],
|
|
231
233
|
cwd: dirname(context.state.adapter.control),
|
|
@@ -253,7 +255,7 @@ async function apply(action, context) {
|
|
|
253
255
|
const before = await readPlayback(context.state.adapter, context.run);
|
|
254
256
|
const result = await context.run({
|
|
255
257
|
command: context.state.adapter.node,
|
|
256
|
-
args: [context.state.adapter.control,
|
|
258
|
+
args: [context.state.adapter.control, "control", context.state.adapter.stateDir, action],
|
|
257
259
|
cwd: dirname(context.state.adapter.control),
|
|
258
260
|
timeoutMs: 5_000,
|
|
259
261
|
});
|