Skip to content

Packages deliver the guidance artifacts for using them #1114

Description

@williamthorsen

Problem

Agent guidance has producers: the project, the user, codeassembly's own library, and the repo's dependencies. Only the dependencies have no route in. A package that ships agent guidance has to invent its own bridge -- nmr generates a version-stamped file into .agents/nmr/ and asks the consuming repo to hand-wire an @import -- and every such package reinvents it, wired per repo by hand.

Context

sources in codeassembly.yaml already resolves a named directory to artifacts, searched ahead of the built-in library, and resolveSourcePath applies no constraints, so path: ../node_modules/@williamthorsen/nmr is legal today. What is missing is a robust route and a package-side convention: the path is hand-written, brittle under hoisting and workspace layouts, and nothing tells a package author what shape to ship.

The pieces a package-shaped source needs already exist and are type-blind. createSourceResolver.resolve() probes <dir>/artifactFrontmatterPath(type, slug) across all of ARTIFACT_TYPES, and enumerateCatalogSlugs enumerates a source's own catalog source-scoped -- so "every artifact a package ships" is an existing primitive rather than new work, and accumulateType supplies use/drop/root: for any new declaration block.

Reading from the installed package also changes the freshness guarantee in kind: a version stamp detects divergence after the fact, while a source-pull makes it unrepresentable, since the rendered artifact is a function of what is installed.

No producer exists in this repo, so the change is exercised against fixture packages; nmr's adoption of the convention is a separate repo's work.

Proposed solution

A packages: declaration block naming installed packages -- not discovery from the dependency tree. A declared package resolves through the module resolver to the content directory it ships, joins the source search order below hand-declared sources entries, and seeds the closure with everything in its catalog, so one line naming the package is the whole consumer declaration. Because it is an ordinary declaration block, use, drop, root: true, and the two-tier scope chain apply with no new semantics. Resolution anchors at the domain base, so a home-domain declaration resolves against the home directory.

A package opts in by declaring a codeassembly.content path in its package.json, pointing at a directory structured like the library's content/. There is no default location: the convention imposes no directory on a package's root, and a producer can nest the content under a directory it already owns.

Because a workspace:* self-link is indistinguishable from an external dependency at resolution, a producing repo consumes its own guidance through the same one-line declaration a third party writes, resolving to the live source directory rather than a packed copy.

Discovery of guidance-shipping dependencies is advisory: sync reports direct dependencies that ship content and are not declared, printing the declaration that would adopt each. Declaration rather than auto-sourcing keeps a dependency from contributing agent instructions, or shadowing an already-declared slug, without a statement in the config -- and it leaves the sources list the one place a reader learns what is in play, since slugs are provenance-free by design.

Granularity is all-or-nothing: adopting a package takes everything it ships. packages: drop: removes a package, but an individual artifact its catalog contributed cannot be dropped, matching the existing limitation on collection members.

Acceptance criteria

Must have

  • A repo adopts a guidance-shipping package by naming it in packages:, with no hand-written filesystem path.
  • Package resolution goes through the module resolver, holding under pnpm hoisting, pnpm's symlinked layout, and workspace:* links.
  • A package that ships guidance and no importable JS entry point resolves.
  • A declared package's content directory participates in the existing source precedence and shadow detection, ranked below hand-declared sources entries and above the library.
  • Precedence among declared packages follows the same tier and declaration ordering as sources.
  • use, drop, and root: true apply to packages: as to any declaration block, in both tiers of a domain.
  • All four artifact types resolve through the same path, with no per-type special-casing.
  • A declared package that is not installed, declares no codeassembly.content, or points at a missing directory fails the run before any write, naming what was searched.
  • sync reports direct dependencies that declare content and are absent from packages:, showing the declaration that adopts them.
  • A dropped package draws no discovery advice.
  • The packages: key and the package-author convention are documented, for consumers and producers respectively.
  • New/modified behavior in this change is covered by tests.

Should have

  • A hand-declared sources entry keeps working, so packages: adds a route rather than replacing one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureAdded or improved external functionalityscope:agents

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions