Commit db0208f
feat(experimental):
* feat(experimental): copilot-app target deploys scheduled prompts to App DB
Dark-shipped under the new `copilot_app` experimental flag (off by default).
When enabled, `apm install --target copilot-app --global` writes prompts
that carry a `schedule:` frontmatter block as rows in the GitHub Copilot
desktop App's SQLite store at `~/.copilot/data.db`. No new CLI surface;
`install` / `update` / `uninstall` / `list` all flow through unchanged.
Hard contracts:
- `enabled = 0` on every insert -- user opts in from the App.
- Namespaced ids (`apm--<owner>--<pkg>--<prompt>`) so uninstall never
touches user-authored rows.
- `PRAGMA user_version` guard (13 currently); refuse to write on unknown.
- WAL-safe SQLite with retry on `database is locked`.
- Update path preserves user state (`enabled`, `last_run_at`, overrides).
- Lockfile URIs use `copilot-app-db://workflows/<id>` (cowork precedent).
Tests: 53 new (DB module, schedule parser, target gating, install E2E).
Full unit suite: 8787 passed (one pre-existing macOS shlex failure
unrelated to this change).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs(copilot-app): integration page, apm-usage skill, error UX + lockfile tests
Wave 4 + Wave 6a of the copilot-app dark-ship:
- docs/src/content/docs/integrations/copilot-app.md mirrors the
copilot-cowork page: enable flag, lifecycle, DB resolution, 'auth'
model, schema guard, concurrency, lockfile URI scheme, out-of-scope.
- apm-usage skill: commands.md notes copilot-app under experimental;
package-authoring.md documents the optional schedule: frontmatter
block.
- tests/unit/integration/test_copilot_app_error_ux.py (5 tests)
exercises CopilotAppDbMissingError, CopilotAppDbSchemaError,
CopilotAppDbLockedError mid-deploy: each surfaces as an actionable
per-prompt diagnostic; one failing prompt does not block the next;
resolver returning None mid-run is defensive (no crash).
- tests/unit/install/test_services.py adds a round-trip test for
copilot-app-db:// URI generation through _deployed_path_entry.
Full unit suite: 8794 passed (1 pre-existing unrelated macOS skip).
Lint contract green.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(copilot-app): preserve URI scheme for user-scope local installs
When 'apm install <local-pkg> --target copilot-app --global' was invoked,
the lockfile stored 'workflows/apm--...' without the 'copilot-app-db://'
scheme prefix. As a result, the subsequent uninstall could not detect the
copilot-app entry and the DB row was orphaned in the Copilot App.
Root cause: _deployed_path_entry tried 'target_path.relative_to(project_root)'
first. For --global installs, project_root is the user home and the
synthetic copilot-app root (~/.copilot/workflows) sits inside it, so the
relative_to() succeeded and skipped the dynamic-root URI branch entirely.
Fix: detect dynamic-root target match (cowork, copilot-app) before
attempting the project_root-relative encoding. The cowork PathTraversalError
behavior is preserved for the legacy out-of-tree case.
Adds 'test_install_local_pkg_then_uninstall_deletes_db_row' end-to-end
regression covering the install -> lockfile URI -> uninstall -> DB row
deletion roundtrip. Also extends partition_managed_files dynamic-root
branch with the 'prompts_copilot-app' bucket and adds a copilot-app scan
in uninstall engine so user-scope DB-backed targets are cleaned even when
the local apm.yml does not enumerate them.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs(changelog): add experimental copilot-app target entry
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(copilot-app): drop autopilot, reset enabled on content change, ship docs
Address apm-review-panel CEO synthesis for PR #1405:
Security (supply-chain-security-expert blocking):
- Remove 'autopilot' from _VALID_MODES (copilot_app_db.py) and
_VALID_SCHEDULE_MODES (prompt_integrator.py). Earlier docstring
claimed third-party autopilot was policy-blocked but no code
enforced it -- this lands the actual enforcement at the writer.
- deploy_workflow UPDATE branch now compares prompt body, mode,
interval, schedule, model, and reasoning_effort against the
existing row; when any execution-affecting field changes the
user's prior opt-in is revoked (enabled = 0, next_run_at = NULL).
Display-only changes (e.g. just the name) still preserve enabled,
last_run_at, next_run_at. Closes the silent-malicious-update
vector the panel flagged.
Test coverage (test-coverage-expert):
- Split the prior 'preserves enabled across updates' test into
two scenarios that match the new semantics and add a third
test covering schedule changes and a regression test that
pins mode='autopilot' as rejected.
Docs (doc-writer blocking):
- Register copilot-app in the Starlight sidebar.
- Add copilot-app row to experimental flag table and update the
targets-matrix experimental note + auto-detection callout.
- Strip false 'apm list' lifecycle row; replace the 'autopilot
policy-blocked' paragraph with the secure-by-default rationale;
expand the lifecycle table so the content-change reset is
documented; fix two 'copilot_app flag' -> 'copilot-app flag'
kebab-case drifts.
CHANGELOG (devx-ux nit):
- Replace 'apm config set experimental.copilot_app true' with
the canonical 'apm experimental enable copilot-app'.
Tests: 62/62 copilot-app suite green; 1970/1970 integration+install
suite green; lint and format silent.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* iter-3: force enabled=0 at INSERT writer + truthful docs
- copilot_app_db.deploy_workflow INSERT now hardcodes enabled=0 in the
SQL (was: row.enabled passthrough). Defence in depth: a future caller
cannot bootstrap an auto-running APM-deployed row even if the row
dataclass carries enabled=1. The user opt-in path stays the same:
enable from the App UI after install.
- New test: test_insert_forces_enabled_zero_even_if_caller_passes_one.
- Docs (copilot-app.md): lifecycle table row 3 now lists all 7
execution-affecting fields (prompt, schedule, mode, model, reasoning
effort), matching deploy_workflow comparison semantics.
- Docs (copilot-app.md): error wording for locked-DB paraphrased
instead of quoting a string the code never emits.
- Docs (package-authoring.md): YAML example drops the autopilot
comment; rationale aligned with the integrations/copilot-app.md
framing (intentionally not accepted via this target).
Closes iter-2 panel feedback. No blocking findings from any of 8
panelists; this iteration converges the residual recommended items.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(copilot-app): allow project-scope install (lift --global gate)
A team-shared scheduled prompt declared in a project's apm.yml now
deploys to the developer's ~/.copilot/data.db on 'apm install', without
requiring '--global' user-scope install. The previous gate forced every
contributor to repeat the install at user scope to receive workflows
the team had already declared in the manifest.
Architectural change:
- Add TargetProfile.scope_invariant_resolver (default False).
- copilot-app sets scope_invariant_resolver=True because its deploy
root (~/.copilot/data.db) is a user-machine resource that exists
regardless of install intent.
- TargetProfile.for_scope(user_scope=False) now runs user_root_resolver
for scope-invariant targets, populating resolved_deploy_root so the
lockfile enrichment can map the synthetic 'workflows/<id>' path to
the copilot-app-db://workflows/<id> URI.
- Cowork remains scope-sensitive (project-scope cowork still rejected).
Security envelope: the experimental copilot_app flag remains the
single opt-in gate. Removing the --global gate folds two consent
layers (flag + user-scope) into one (flag), which matches v1's stated
'apm install just works' UX promise. The DB row is still INSERTed with
enabled=0, the namespaced 'apm--<owner>--<pkg>--<prompt>' ID is
preserved, and the lockfile URI keeps uninstall surgical.
Tests:
- 8801 unit tests pass (full sweep).
- 64 copilot-app tests pass (was 63).
- New test_install_project_scope_then_uninstall_deletes_db_row
exercises the full roundtrip via project apm.yml + chdir; rewrites
the prior test_project_scope_requires_global which asserted the
inverse.
- Manual verification in /tmp: install -> DB row appears with
enabled=0 -> uninstall -> DB row gone.
Docs:
- integrations/copilot-app.md install incantation updated.
- apm-usage skill commands.md + package-authoring.md mention both
project and user scope.
- CHANGELOG entry rewritten.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(copilot-app): address devx-ux follow-ups on gate-lift
Two recommended findings from devx-ux-expert re-panel (Opus 4.7,
agent_id devx-on-gate-lift):
1. Install output is silent about the 'enable in Copilot App' step.
Added one-line trailing hint after the 'N prompts integrated ->
copilot-app/workflows/' line, only when copilot-app actually wrote
rows in this run:
[+] /pkg (local)
|-- 1 prompts integrated -> copilot-app/workflows/
|-- workflows arrive disabled; enable from the Copilot App's
Workflows tab
This closes the first-contributor failure mode that the gate-lift
surfaces (someone runs plain 'apm install' on a project that
declares copilot-app in targets, sees the integrated line, doesn't
realise the row landed enabled=0 and needs a Copilot App toggle to
fire).
2. targets-matrix.md docs row understated project-scope ride-along
for the three never-auto-detected targets. Reworded to call out
that a project apm.yml 'targets:' field lets contributors pick
them up via plain 'apm install'.
Plus the test-coverage nit: pinned verbatim install output shape in
the new project-scope roundtrip test (asserts 'prompts integrated'
AND 'enable from the Copilot App' appear).
Verification:
- 64 copilot-app tests pass
- Full unit sweep 8800 pass (1 pre-existing flake on
test_runtime_windows.py unrelated to gate-lift -- fails on
fc40650d too because local 'codex' binary is installed)
- Lint+format silent
- Manual e2e:
[+] /pkg (local)
|-- 1 prompts integrated -> copilot-app/workflows/
|-- workflows arrive disabled; enable from the Copilot App's Workflows tab
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(copilot-app): narrow workflow-shape predicate to 3 keys
Option B refinement: distinguish workflow-shape prompts from plain
.prompt.md unambiguously. Only {interval, schedule_hour, schedule_day}
mark a prompt as a Copilot App workflow row; `mode` and
`reasoning_effort` are valid OPTIONAL fields on a workflow but cannot
flip the shape because plain VSCode prompts use `mode: agent|ask|edit`
legitimately.
Without this narrow, any plain prompt that set `mode:` would silently
land as a (broken) workflow when the user passed --target copilot-app,
or a workflow row could be lossy when a writer set only `mode:`.
Live e2e verified:
- Single-target copilot: workflow-shape SKIPPED, plain ships to
.github/prompts/ correctly.
- Single-target copilot-app: workflow row in ~/.copilot/data.db with
enabled=0; plain prompt warns then skips.
- Multi-target copilot,copilot-app (comma-separated): both dispatch
paths fire; no leak between them.
- Update preserves user-side enabled=1 across re-install.
- Lockfile records copilot-app-db:// URIs cleanly; apm audit clean.
Warning text narrowed to actually-mandatory keys so the hint is
truthful and reproducible.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* address panel follow-ups: devx-ux, test-coverage, doc-writer
- install.py --target help: mention copilot-app + warn that repeated
flag (-t a -t b) silently honors only the last value; use commas
(devx-ux #1, #2)
- copilot-app.md: bump sidebar order 5 -> 6 (collision with
github-rulesets.md), cross-link to reference/experimental/ and
reference/targets-matrix/, rephrase WAL ownership to reflect that
the App owns WAL and APM coexists via BEGIN IMMEDIATE + bounded
retry, surface accepted schema range [13, 13], split lifecycle
table cell with rationale below the table, add :::note callout
clarifying the shape predicate, document source-deletion orphan
case (doc-writer #1-5, devx-ux #4, #5)
- tests: add test_workflow_shape_skipped_by_copilot_prompt_integrator
regression test asserting workflow-shape .prompt.md does NOT leak
into .github/prompts/ when --target includes copilot
(test-coverage #1)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Daniel Meppiel <copilot-rework@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>copilot-app target deploys scheduled prompts to App DB (#1405)1 parent 9d1ae4e commit db0208f
27 files changed
Lines changed: 2892 additions & 15 deletions
File tree
- docs
- src/content/docs
- integrations
- reference
- packages/apm-guide/.apm/skills/apm-usage
- src/apm_cli
- commands
- uninstall
- core
- install
- phases
- integration
- tests/unit
- core
- install
- integration
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
10 | 18 | | |
11 | 19 | | |
| 20 | + | |
| 21 | + | |
12 | 22 | | |
13 | 23 | | |
14 | 24 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
211 | 211 | | |
212 | 212 | | |
213 | 213 | | |
| 214 | + | |
214 | 215 | | |
215 | 216 | | |
216 | 217 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
171 | 171 | | |
172 | 172 | | |
173 | 173 | | |
| 174 | + | |
174 | 175 | | |
175 | 176 | | |
176 | 177 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | | - | |
36 | | - | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
| |||
60 | 61 | | |
61 | 62 | | |
62 | 63 | | |
63 | | - | |
64 | | - | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
65 | 68 | | |
66 | 69 | | |
67 | 70 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
141 | 141 | | |
142 | 142 | | |
143 | 143 | | |
| 144 | + | |
| 145 | + | |
144 | 146 | | |
145 | 147 | | |
146 | 148 | | |
| |||
Lines changed: 38 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
180 | 180 | | |
181 | 181 | | |
182 | 182 | | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
183 | 221 | | |
184 | 222 | | |
185 | 223 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
927 | 927 | | |
928 | 928 | | |
929 | 929 | | |
930 | | - | |
| 930 | + | |
931 | 931 | | |
932 | 932 | | |
933 | 933 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
515 | 515 | | |
516 | 516 | | |
517 | 517 | | |
518 | | - | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
519 | 523 | | |
520 | 524 | | |
521 | 525 | | |
| |||
579 | 583 | | |
580 | 584 | | |
581 | 585 | | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
582 | 617 | | |
583 | 618 | | |
584 | 619 | | |
| |||
0 commit comments