Skip to content

fix(packaging): drop non-existent uv workspace members (v0.4.1)#35

Merged
manojp99 merged 2 commits into
mainfrom
fix/uv-workspace-cleanup-0.4.1
Jun 3, 2026
Merged

fix(packaging): drop non-existent uv workspace members (v0.4.1)#35
manojp99 merged 2 commits into
mainfrom
fix/uv-workspace-cleanup-0.4.1

Conversation

@manojp99

@manojp99 manojp99 commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Patch release 0.4.1 fixing a uv tool install failure reported by a consumer of v0.4.0.

The bug

pyproject.toml at v0.4.0 (= caa9d45) declared three workspace members:

[tool.uv.workspace]
members = ['packages/amplifier-agent', 'packages/amplifier-agent-session-spawner', 'wrappers/python']

But the two packages/... directories have never existed in this repository — the declaration has been wrong since 04d079b (the original Phase 1-4 implementation commit). Only wrappers/python is a real workspace member.

Symptom

Most uv versions are graceful about non-existent workspace members (warn or silently skip). But specific uv-version + config combinations resolve the workspace install path to an ancestor commit. The consumer hit 2bd951f — a commit predating PR #27's wheel-build fix, where the duplicate force-include entries for protocol/schemas/ and protocol/conformance/fixtures/ were still present. Hatchling hard-errors on those duplicates with "A second file is being added to the wheel archive at the same path", masking the real cause (the dead workspace members).

Fix

Drop the two non-existent members. Declare only wrappers/python.

[tool.uv.workspace]
members = ['wrappers/python']

Engine version bumped 0.4.00.4.1. No code changes elsewhere. No wire-protocol change. TS wrapper unaffected (different package, different release track).

Tests

Suite Result
Engine 532 passed, 3 skipped
Python wrapper 54 passed
TS wrapper 66 passed (12 files)
Conformance TS 7 passed
Conformance Py 7 passed

Plus the consumer-reproduction uv tool install --from "$(pwd)" amplifier-agent succeeds cleanly on this branch (verified locally after uv cache clean; installed v0.4.1 with both amplifier-agent and amplifier-agent-post-install executables).

Consumer guidance

Consumers who hit uv tool install failures with v0.4.0 should retry with v0.4.1. No code changes needed on the consumer side. After this PR merges, push v0.4.1 tag to trigger the GitHub Release.

Why this slipped past CI

  • The dead workspace members didn't cause our test suites to fail because we don't have a uv tool install integration test in CI — only uv sync --all-extras --dev, which tolerates the missing members differently.
  • The wheel-build fix (PR feat: host config layer + drop hostCapabilities surface #27, commit 05dd153) verified the top-level pyproject.toml. But workspace resolution can route uv to other commits where the fix isn't applied yet.
  • Worth surfacing as a follow-up: add a uv tool install smoke test to CI that mirrors the consumer install path. Tracked separately.

release added 2 commits June 3, 2026 14:50
The [tool.uv.workspace] block declared three members but only
wrappers/python actually exists in the tree. The two packages/...
entries have never existed at any commit. Most uv versions tolerate
this (warn or silently skip), but specific uv-version + config
combinations would resolve the workspace install to an ancestor
commit where pre-PR-#27 wheel-build duplicates were still present,
producing confusing hatchling errors at uv tool install time.

Declare only the real member: wrappers/python.
@manojp99 manojp99 merged commit 99abe41 into main Jun 3, 2026
3 checks passed
manojp99 added a commit that referenced this pull request Jun 10, 2026
…ce hook (with fork-pin disclosure) (#46)

* docs: add workspace identity and storage flexibility design

Companion to the workspace resolution + migration design. Explains the
extensibility properties of the workspace identity layer: additive scope
expansion (tenant/user keys), discovery as a separate concern, per-workspace
config as an additive layer, and the session.storage capability as the
substitution seam for non-filesystem backends (SQLite, HTTP, virtual).
Documents the identity/backend separation invariant (I1) and concrete
migration scenarios proving today's design does not paint into a corner.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* docs: add workspace resolution and migration design

Core technical design for per-session workspace identity resolution
(argv > env > cwd-derived) and migration of the flat sessions/<id>/
layout to workspaces/<workspace>/sessions/<id>/. Companion to the
workspace identity and storage flexibility design.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* docs(design): unify session layout — audits and --fresh follow workspace convention

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* docs(plan): add B4/B5/E6 — unify audit and --fresh under workspace tree

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(persistence): add workspaces_root() helper (D8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(persistence): add WorkspaceError + validate_slug (D3)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* style(persistence): ruff-format validate_slug raise + add 64-char boundary test

Squashes A2 ruff-format violation and closes the upper-bound coverage gap
flagged by the code quality reviewer.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(persistence): add slugify + derive_workspace_from_cwd (D4)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* refactor(persistence): make slugify module-private + strip trailing hyphen

Renames slugify → _slugify (module-private; only called by
derive_workspace_from_cwd, no external imports). Documents the
non-ASCII stripping behavior in the docstring. Strips a trailing
hyphen from slug_base after the 48-char truncation so the
separator stays single.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(persistence): add resolve_workspace top-level resolver (D2)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(persistence): symmetric whitespace handling + invalid-env test

Closes the asymmetry flagged by code quality review on 0bda100:
whitespace-only argv now falls through (was: raised), matching
the existing whitespace-env behavior. Adds the missing symmetric
test for invalid env slug.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(cli): add --workspace flag to run, thread to _TurnSpec (D1)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(cli): correct B1 test scaffolding + user-facing --workspace help

The previous "errors cleanly" test passed for the wrong reason (sk-test
401 from Anthropic, not slug validation). Rewrites the test to patch
_execute_turn and assert the B1 contract: invalid slugs pass through
unchanged at the CLI layer (B4 adds fail-fast validation later).

Also updates the --workspace help text from a design-doc reference to
a user-facing description visible at terminal --help.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(runtime): resolve workspace, write workspace + project_slug to coordinator.config (D5, D6, D8)

Also update existing runtime tests to reflect the new per-workspace SessionStore
root (D8): tests that pre-populate or check persisted transcripts now use
tmp_path/workspaces/<workspace>/sessions/<id>/ rather than the flat
tmp_path/sessions/<id>/ layout, and _FakeCoordinator gains a config dict so
the D5 dual-key write does not AttributeError.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(runtime): typed ctx in workspace tests + merge duplicate assertions + env-var coverage

Addresses B2 code quality review:
- Wraps SimpleNamespace ctx with cast(TurnContext, ...) to fix 3 pyright
  reportArgumentType errors that were silently passing.
- Merges two duplicate config-key tests into one that asserts both D5
  keys (workspace + project_slug alias) in a single setup.
- Adds env-var fallback test at handler level — covers the
  AMPLIFIER_AGENT_WORKSPACE → SessionStore path that was previously
  dark at the integration layer.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(session-store): anchor per-workspace root layout (D8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(runtime): move audit write path to per-workspace tree (workspace I8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(runtime): scope --fresh cleanup to per-workspace session dir (workspace I8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* refactor(runtime): drop redundant resolve_workspace re-import + symmetry pass

Addresses B5 code quality review:
- Removes the local re-import of resolve_workspace (already at module
  scope from B4); only workspaces_root is imported locally.
- Adds a one-line comment explaining why no WorkspaceError guard is
  needed here (fail-fast happens upstream in run()).
- Renames workspace → resolved_workspace in the --fresh block to match
  the parallel pattern in run().

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(spawn): propagate workspace to child coordinators verbatim (D7)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(migration): add migrate_legacy_sessions_if_needed (D9, flock-guarded, idempotent)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(session-store): cross-workspace load fallback (D10)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* refactor(session-store): hoist workspaces_root import + drop false cycle comment

Addresses D2 code quality review: the local-import-with-cycle-warning
comment was factually wrong. No cycle exists between session_store and
persistence; persistence does not import from session_store at any level.
The live-XDG_STATE_HOME claim also doesn't hold — workspaces_root() is a
function, so the call resolves env at invocation time regardless of import
placement. Moves the import to module level and removes the misleading
comment.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(runtime): trigger legacy-sessions migration once per process (D9)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): --workspace flag produces workspaces/<ws> layout (D1, D8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): AMPLIFIER_AGENT_WORKSPACE env var layout (D1, D2)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): cwd-derived workspace is stable across invocations (D4, I5)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): legacy sessions migrated to _legacy on first boot (D9)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): cross-workspace resume finds migrated session (D10)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): audit file lands under workspace tree after real turn (I8, SC-H)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(tests): update broken audit-path tests + ruff-format test_spawn.py

Surfaced during E1-E6 final verification:
- test_mode_a_audit_trail.py and test_drop_host_capabilities.py asserted
  against the flat audit path that B4 changed. Update both to use the
  workspace-scoped layout (--workspace test-ws + workspaces/<ws>/...
  path computation).
- test_spawn.py had a pre-existing ruff-format violation. Auto-format
  applied; whitespace-only diff.

These are pre-existing regressions introduced by earlier sections (B4
and C1 respectively) that focused test runs missed. Caught during the
full-suite gate at the end of the plan.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(bundle): integrate hook-context-intelligence for local-only event logging

Adds hook-context-intelligence (pinned to v0.1.1) to the sealed bundle for
local-only event logging - JSONL events captured alongside transcripts and
audits in the workspace tree (invariant I8 unification).

Configuration:
- log_level: INFO
- base_path: ${XDG_STATE_HOME:~/.local/state}/amplifier-agent/workspaces
  Tracks AAA's own XDG_STATE_HOME so events relocate with the rest of state.
- additional_events: delegate lifecycle (5 events). Built-in kernel events
  (tool calls, LLM responses) auto-captured from amplifier_core.events.ALL_EVENTS.
- No server URL or API key - local-only mode. HTTP dispatch can be lit up
  later via AMPLIFIER_CONTEXT_INTELLIGENCE_SERVER_URL + ..._API_KEY env vars
  without a bundle.md change.

Final on-disk layout (events.jsonl alongside transcript + audits):
  $XDG_STATE_HOME/amplifier-agent/workspaces/<workspace>/sessions/<id>/
    transcript.jsonl              (IncrementalSaveHook)
    metadata.json
    audits/turn-<id>.json         (per-turn audit, I8)
    context-intelligence/         (NEW)
      events.jsonl
      metadata.json

project_slug is auto-resolved from coordinator.config["project_slug"] which
the workspace work (D5 dual-key write in B2) sets to the AAA workspace slug.
No manual configuration of project_slug needed - zero-config alignment with
the workspace identity.

Honors:
- I3: AAA's state stays in its own tree (not coupled to amplifier-app-cli's
  ~/.amplifier/ tree).
- I8: All per-session artifacts live in the unified workspace layout.
- D4 of 2026-05-19-baked-in-bundle-decision.md: pinned tag (v0.1.1) for
  sealed-bundle discipline.

Bumps bundle version 1.2.1 -> 1.3.0 (first AAA-only addition beyond
upstream build-up-foundation parity).

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(bundle): point hook-context-intelligence at upstream PR branch for testing

Temporary pin: re-points the hook source from microsoft/...@v0.1.1 to
manojp99/...@proposal/decouple-hook-from-parent-bundle so the DTU can
verify the integration end-to-end while the upstream proposal awaits
maintainer review.

Upstream PR: microsoft/amplifier-bundle-context-intelligence#35
Diagnostic:  microsoft-amplifier/amplifier-support#269

The PR removes the bogus amplifier-bundle-context-intelligence runtime
dependency (and its corresponding [tool.uv.sources] entry) from the hook
module, plus inverts three test assertions to lock the new contract.
Decoupling allows the hook to install under --no-sources, which AAA's
foundation activator uses by documented policy.

Re-point to a stable upstream tag (e.g. @v0.1.2) once the PR merges.
This temporary pin should NOT ship in a release of amplifier-agent;
either squash with b7b356b when re-pointing, or revert+re-apply against
the merged tag.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(bundle): pin hook source to @3a94d0d (vendoring fix on PR #35)

PR #35's branch now has two commits:
  45b038f - removes the bogus amplifier-bundle-context-intelligence runtime
            dep (fixes install layer under --no-sources)
  3a94d0d - vendors the 4 symbols the hook actually imports from
            context_intelligence into a local _vendored.py module
            (fixes mount layer under --no-sources)

Together they let the hook install AND mount cleanly without the parent
bundle on PYTHONPATH. Pinning to the SHA instead of the branch name
ensures:
  1. The bundle cache (sha256-keyed) self-invalidates and pulls the new
     source on next prepare.
  2. We are locked to a specific known-good state rather than tracking
     whatever HEAD of the proposal branch happens to be.

Re-test in DTU pending. When upstream PR merges, re-point to whatever
stable tag carries the merged code (e.g. @v0.1.2).

Refs:
- microsoft/amplifier-bundle-context-intelligence#35
- microsoft-amplifier/amplifier-support#269

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(integration): re-point hook source + literal base_path + project_slug timing

Three integration bugs surfaced when the context-intelligence hook actually
ran for the first time (after PR #35's vendoring fix unblocked install
and mount):

A. bundle.md pinned source via raw SHA (@3a94d0d), but foundation's
   git source resolver uses git clone --branch <ref> and --branch
   does not accept SHAs. Reverts da7d9d8; source now uses the branch
   name @proposal/decouple-hook-from-parent-bundle.

B. base_path used "${XDG_STATE_HOME:~/.local/state}/..." but neither
   foundation's preprocessor nor the hook's expanduser() expand
   ${VAR:default} syntax. The literal string survived as a directory
   segment. Replaces with "~/.local/state/amplifier-agent/workspaces"
   (XDG_STATE_HOME override is documented as not tracked).

C. Hook reads coordinator.config["project_slug"] lazily, caching on
   first access. The D5 write happened after prepared.create_session()
   returned, but session:start fires inside create_session() during
   initialize() — so the hook cached the working_dir slug (bundle
   install dir) before the write landed.

   create_session() has no coordinator_config parameter (Approach 1
   not available). Fix uses Approach 2: inject project_slug and
   workspace directly into hook-context-intelligence's own module
   config in mount_plan at handler-creation time (outside the per-turn
   handler closure). The hook's fallback chain reads config['project_slug']
   FIRST — before coordinator.config — so the injected value is seen
   at session:start even before coordinator.config is written.
   The D5 coordinator.config writes are preserved as a belt-and-
   suspenders write for other consumers.

Net effect after these three fixes: events.jsonl should land at
~/.local/state/amplifier-agent/workspaces/<workspace>/sessions/<id>/context-intelligence/
co-located with transcript.jsonl and audits/.

Re-test in DTU pending.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(bundle): expand TODO marker for upstream-pr-35 fork pin

Makes the temporary fork-pin grep-able as TODO(upstream-pr-35) and lists
the exact 4 steps needed to re-point this source when upstream PR #35
merges. The pin itself is unchanged; this is documentation only.

Rationale: shipping the AAA PR with a fork-pin in bundle.md is honest
(the workspace work is the primary value of this PR, the hook integration
is a bonus), but the transient state needs to be findable and actionable
when upstream resolves.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

---------

Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com>
Co-authored-by: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
manojp99 pushed a commit that referenced this pull request Jun 10, 2026
…nstall branch

The maintainer cut their own fix branch with a different (and cleaner)
approach than PR #35's vendoring proposal. Their fix (commit 3fbe170 on
fix/hook-standalone-install):

- Converts the bare-name "amplifier-bundle-context-intelligence" dep to a
  PEP 508 direct git reference:
    amplifier-bundle-context-intelligence @ git+https://github.com/microsoft/amplifier-bundle-context-intelligence@v0.1.1
- Adds [tool.hatch.metadata] allow-direct-references = true
- Removes the [tool.uv.sources] path mapping
- Bumps version 0.1.1 -> 0.1.2

PEP 508 direct-URL refs in [project.dependencies] survive --no-sources
(unlike [tool.uv.sources] entries), so the hook now installs cleanly AND
pulls in the bundle as a transitive dep via git URL — putting
context_intelligence on sys.path automatically. No vendoring needed.

This approach is preferable to PR #35's vendoring because:
  - 1-file change vs 3-file change
  - No drift risk (bundle stays canonical for context_intelligence)
  - Smaller diff, easier review
  - Aligns with the maintainer's stated preference in microsoft-amplifier/amplifier-support#269

Updates TODO marker accordingly. PR #35 should be closed (as superseded)
when fix/hook-standalone-install merges to main. AAA's three integration
fixes (B/B/C) remain unchanged and continue to work.

DTU re-verification pending.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
manojp99 pushed a commit that referenced this pull request Jun 10, 2026
The maintainer's standalone-install fix MERGED to upstream main via PR #36
(commit 0fb5ef60, "fix(hook-context-intelligence): enable standalone
install (decouple from bundle path dependency)"). The fix/hook-standalone-install
branch we were pinned to has been deleted.

No v0.1.2 git tag exists yet. Foundation's source resolver uses
git clone --depth 1 --branch <ref> which accepts branch names and tags
but not raw SHAs, so we can't pin to the merge commit directly.

Temporary pin: @main. Tightens to @v0.1.2 when the maintainer cuts a tag.
TODO marker updated to reflect the new transient state.

Our prior PR #35 (vendoring proposal) is now superseded; closing separately.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
manojp99 added a commit that referenced this pull request Jun 10, 2026
* docs: add workspace identity and storage flexibility design

Companion to the workspace resolution + migration design. Explains the
extensibility properties of the workspace identity layer: additive scope
expansion (tenant/user keys), discovery as a separate concern, per-workspace
config as an additive layer, and the session.storage capability as the
substitution seam for non-filesystem backends (SQLite, HTTP, virtual).
Documents the identity/backend separation invariant (I1) and concrete
migration scenarios proving today's design does not paint into a corner.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* docs: add workspace resolution and migration design

Core technical design for per-session workspace identity resolution
(argv > env > cwd-derived) and migration of the flat sessions/<id>/
layout to workspaces/<workspace>/sessions/<id>/. Companion to the
workspace identity and storage flexibility design.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* docs(design): unify session layout — audits and --fresh follow workspace convention

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* docs(plan): add B4/B5/E6 — unify audit and --fresh under workspace tree

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(persistence): add workspaces_root() helper (D8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(persistence): add WorkspaceError + validate_slug (D3)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* style(persistence): ruff-format validate_slug raise + add 64-char boundary test

Squashes A2 ruff-format violation and closes the upper-bound coverage gap
flagged by the code quality reviewer.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(persistence): add slugify + derive_workspace_from_cwd (D4)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* refactor(persistence): make slugify module-private + strip trailing hyphen

Renames slugify → _slugify (module-private; only called by
derive_workspace_from_cwd, no external imports). Documents the
non-ASCII stripping behavior in the docstring. Strips a trailing
hyphen from slug_base after the 48-char truncation so the
separator stays single.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(persistence): add resolve_workspace top-level resolver (D2)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(persistence): symmetric whitespace handling + invalid-env test

Closes the asymmetry flagged by code quality review on 0bda100:
whitespace-only argv now falls through (was: raised), matching
the existing whitespace-env behavior. Adds the missing symmetric
test for invalid env slug.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(cli): add --workspace flag to run, thread to _TurnSpec (D1)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(cli): correct B1 test scaffolding + user-facing --workspace help

The previous "errors cleanly" test passed for the wrong reason (sk-test
401 from Anthropic, not slug validation). Rewrites the test to patch
_execute_turn and assert the B1 contract: invalid slugs pass through
unchanged at the CLI layer (B4 adds fail-fast validation later).

Also updates the --workspace help text from a design-doc reference to
a user-facing description visible at terminal --help.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(runtime): resolve workspace, write workspace + project_slug to coordinator.config (D5, D6, D8)

Also update existing runtime tests to reflect the new per-workspace SessionStore
root (D8): tests that pre-populate or check persisted transcripts now use
tmp_path/workspaces/<workspace>/sessions/<id>/ rather than the flat
tmp_path/sessions/<id>/ layout, and _FakeCoordinator gains a config dict so
the D5 dual-key write does not AttributeError.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(runtime): typed ctx in workspace tests + merge duplicate assertions + env-var coverage

Addresses B2 code quality review:
- Wraps SimpleNamespace ctx with cast(TurnContext, ...) to fix 3 pyright
  reportArgumentType errors that were silently passing.
- Merges two duplicate config-key tests into one that asserts both D5
  keys (workspace + project_slug alias) in a single setup.
- Adds env-var fallback test at handler level — covers the
  AMPLIFIER_AGENT_WORKSPACE → SessionStore path that was previously
  dark at the integration layer.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(session-store): anchor per-workspace root layout (D8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(runtime): move audit write path to per-workspace tree (workspace I8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(runtime): scope --fresh cleanup to per-workspace session dir (workspace I8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* refactor(runtime): drop redundant resolve_workspace re-import + symmetry pass

Addresses B5 code quality review:
- Removes the local re-import of resolve_workspace (already at module
  scope from B4); only workspaces_root is imported locally.
- Adds a one-line comment explaining why no WorkspaceError guard is
  needed here (fail-fast happens upstream in run()).
- Renames workspace → resolved_workspace in the --fresh block to match
  the parallel pattern in run().

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(spawn): propagate workspace to child coordinators verbatim (D7)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(migration): add migrate_legacy_sessions_if_needed (D9, flock-guarded, idempotent)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(session-store): cross-workspace load fallback (D10)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* refactor(session-store): hoist workspaces_root import + drop false cycle comment

Addresses D2 code quality review: the local-import-with-cycle-warning
comment was factually wrong. No cycle exists between session_store and
persistence; persistence does not import from session_store at any level.
The live-XDG_STATE_HOME claim also doesn't hold — workspaces_root() is a
function, so the call resolves env at invocation time regardless of import
placement. Moves the import to module level and removes the misleading
comment.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(runtime): trigger legacy-sessions migration once per process (D9)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): --workspace flag produces workspaces/<ws> layout (D1, D8)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): AMPLIFIER_AGENT_WORKSPACE env var layout (D1, D2)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): cwd-derived workspace is stable across invocations (D4, I5)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): legacy sessions migrated to _legacy on first boot (D9)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): cross-workspace resume finds migrated session (D10)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* test(integration): audit file lands under workspace tree after real turn (I8, SC-H)

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(tests): update broken audit-path tests + ruff-format test_spawn.py

Surfaced during E1-E6 final verification:
- test_mode_a_audit_trail.py and test_drop_host_capabilities.py asserted
  against the flat audit path that B4 changed. Update both to use the
  workspace-scoped layout (--workspace test-ws + workspaces/<ws>/...
  path computation).
- test_spawn.py had a pre-existing ruff-format violation. Auto-format
  applied; whitespace-only diff.

These are pre-existing regressions introduced by earlier sections (B4
and C1 respectively) that focused test runs missed. Caught during the
full-suite gate at the end of the plan.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* feat(bundle): integrate hook-context-intelligence for local-only event logging

Adds hook-context-intelligence (pinned to v0.1.1) to the sealed bundle for
local-only event logging - JSONL events captured alongside transcripts and
audits in the workspace tree (invariant I8 unification).

Configuration:
- log_level: INFO
- base_path: ${XDG_STATE_HOME:~/.local/state}/amplifier-agent/workspaces
  Tracks AAA's own XDG_STATE_HOME so events relocate with the rest of state.
- additional_events: delegate lifecycle (5 events). Built-in kernel events
  (tool calls, LLM responses) auto-captured from amplifier_core.events.ALL_EVENTS.
- No server URL or API key - local-only mode. HTTP dispatch can be lit up
  later via AMPLIFIER_CONTEXT_INTELLIGENCE_SERVER_URL + ..._API_KEY env vars
  without a bundle.md change.

Final on-disk layout (events.jsonl alongside transcript + audits):
  $XDG_STATE_HOME/amplifier-agent/workspaces/<workspace>/sessions/<id>/
    transcript.jsonl              (IncrementalSaveHook)
    metadata.json
    audits/turn-<id>.json         (per-turn audit, I8)
    context-intelligence/         (NEW)
      events.jsonl
      metadata.json

project_slug is auto-resolved from coordinator.config["project_slug"] which
the workspace work (D5 dual-key write in B2) sets to the AAA workspace slug.
No manual configuration of project_slug needed - zero-config alignment with
the workspace identity.

Honors:
- I3: AAA's state stays in its own tree (not coupled to amplifier-app-cli's
  ~/.amplifier/ tree).
- I8: All per-session artifacts live in the unified workspace layout.
- D4 of 2026-05-19-baked-in-bundle-decision.md: pinned tag (v0.1.1) for
  sealed-bundle discipline.

Bumps bundle version 1.2.1 -> 1.3.0 (first AAA-only addition beyond
upstream build-up-foundation parity).

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(bundle): point hook-context-intelligence at upstream PR branch for testing

Temporary pin: re-points the hook source from microsoft/...@v0.1.1 to
manojp99/...@proposal/decouple-hook-from-parent-bundle so the DTU can
verify the integration end-to-end while the upstream proposal awaits
maintainer review.

Upstream PR: microsoft/amplifier-bundle-context-intelligence#35
Diagnostic:  microsoft-amplifier/amplifier-support#269

The PR removes the bogus amplifier-bundle-context-intelligence runtime
dependency (and its corresponding [tool.uv.sources] entry) from the hook
module, plus inverts three test assertions to lock the new contract.
Decoupling allows the hook to install under --no-sources, which AAA's
foundation activator uses by documented policy.

Re-point to a stable upstream tag (e.g. @v0.1.2) once the PR merges.
This temporary pin should NOT ship in a release of amplifier-agent;
either squash with b7b356b when re-pointing, or revert+re-apply against
the merged tag.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(bundle): pin hook source to @3a94d0d (vendoring fix on PR #35)

PR #35's branch now has two commits:
  45b038f - removes the bogus amplifier-bundle-context-intelligence runtime
            dep (fixes install layer under --no-sources)
  3a94d0d - vendors the 4 symbols the hook actually imports from
            context_intelligence into a local _vendored.py module
            (fixes mount layer under --no-sources)

Together they let the hook install AND mount cleanly without the parent
bundle on PYTHONPATH. Pinning to the SHA instead of the branch name
ensures:
  1. The bundle cache (sha256-keyed) self-invalidates and pulls the new
     source on next prepare.
  2. We are locked to a specific known-good state rather than tracking
     whatever HEAD of the proposal branch happens to be.

Re-test in DTU pending. When upstream PR merges, re-point to whatever
stable tag carries the merged code (e.g. @v0.1.2).

Refs:
- microsoft/amplifier-bundle-context-intelligence#35
- microsoft-amplifier/amplifier-support#269

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* fix(integration): re-point hook source + literal base_path + project_slug timing

Three integration bugs surfaced when the context-intelligence hook actually
ran for the first time (after PR #35's vendoring fix unblocked install
and mount):

A. bundle.md pinned source via raw SHA (@3a94d0d), but foundation's
   git source resolver uses git clone --branch <ref> and --branch
   does not accept SHAs. Reverts da7d9d8; source now uses the branch
   name @proposal/decouple-hook-from-parent-bundle.

B. base_path used "${XDG_STATE_HOME:~/.local/state}/..." but neither
   foundation's preprocessor nor the hook's expanduser() expand
   ${VAR:default} syntax. The literal string survived as a directory
   segment. Replaces with "~/.local/state/amplifier-agent/workspaces"
   (XDG_STATE_HOME override is documented as not tracked).

C. Hook reads coordinator.config["project_slug"] lazily, caching on
   first access. The D5 write happened after prepared.create_session()
   returned, but session:start fires inside create_session() during
   initialize() — so the hook cached the working_dir slug (bundle
   install dir) before the write landed.

   create_session() has no coordinator_config parameter (Approach 1
   not available). Fix uses Approach 2: inject project_slug and
   workspace directly into hook-context-intelligence's own module
   config in mount_plan at handler-creation time (outside the per-turn
   handler closure). The hook's fallback chain reads config['project_slug']
   FIRST — before coordinator.config — so the injected value is seen
   at session:start even before coordinator.config is written.
   The D5 coordinator.config writes are preserved as a belt-and-
   suspenders write for other consumers.

Net effect after these three fixes: events.jsonl should land at
~/.local/state/amplifier-agent/workspaces/<workspace>/sessions/<id>/context-intelligence/
co-located with transcript.jsonl and audits/.

Re-test in DTU pending.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(bundle): expand TODO marker for upstream-pr-35 fork pin

Makes the temporary fork-pin grep-able as TODO(upstream-pr-35) and lists
the exact 4 steps needed to re-point this source when upstream PR #35
merges. The pin itself is unchanged; this is documentation only.

Rationale: shipping the AAA PR with a fork-pin in bundle.md is honest
(the workspace work is the primary value of this PR, the hook integration
is a bonus), but the transient state needs to be findable and actionable
when upstream resolves.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(bundle): re-point hook source to upstream fix/hook-standalone-install branch

The maintainer cut their own fix branch with a different (and cleaner)
approach than PR #35's vendoring proposal. Their fix (commit 3fbe170 on
fix/hook-standalone-install):

- Converts the bare-name "amplifier-bundle-context-intelligence" dep to a
  PEP 508 direct git reference:
    amplifier-bundle-context-intelligence @ git+https://github.com/microsoft/amplifier-bundle-context-intelligence@v0.1.1
- Adds [tool.hatch.metadata] allow-direct-references = true
- Removes the [tool.uv.sources] path mapping
- Bumps version 0.1.1 -> 0.1.2

PEP 508 direct-URL refs in [project.dependencies] survive --no-sources
(unlike [tool.uv.sources] entries), so the hook now installs cleanly AND
pulls in the bundle as a transitive dep via git URL — putting
context_intelligence on sys.path automatically. No vendoring needed.

This approach is preferable to PR #35's vendoring because:
  - 1-file change vs 3-file change
  - No drift risk (bundle stays canonical for context_intelligence)
  - Smaller diff, easier review
  - Aligns with the maintainer's stated preference in microsoft-amplifier/amplifier-support#269

Updates TODO marker accordingly. PR #35 should be closed (as superseded)
when fix/hook-standalone-install merges to main. AAA's three integration
fixes (B/B/C) remain unchanged and continue to work.

DTU re-verification pending.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

* chore(bundle): re-point hook source to upstream main (post-merge)

The maintainer's standalone-install fix MERGED to upstream main via PR #36
(commit 0fb5ef60, "fix(hook-context-intelligence): enable standalone
install (decouple from bundle path dependency)"). The fix/hook-standalone-install
branch we were pinned to has been deleted.

No v0.1.2 git tag exists yet. Foundation's source resolver uses
git clone --depth 1 --branch <ref> which accepts branch names and tags
but not raw SHAs, so we can't pin to the merge commit directly.

Temporary pin: @main. Tightens to @v0.1.2 when the maintainer cuts a tag.
TODO marker updated to reflect the new transient state.

Our prior PR #35 (vendoring proposal) is now superseded; closing separately.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

---------

Co-authored-by: Manoj Prabhakar Paidiparthy <mpaidiparthy@microsoft.com>
Co-authored-by: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant