Skip to content

feat: add codefly:solution agent kind (#287) - #288

Merged
antoinetoussaint-byte merged 2 commits into
mainfrom
issue-287-new-agent-kind-codefly-solution-registry-entry-proto
Aug 16, 2026
Merged

feat: add codefly:solution agent kind (#287)#288
antoinetoussaint-byte merged 2 commits into
mainfrom
issue-287-new-agent-kind-codefly-solution-registry-entry-proto

Conversation

@antoinetoussaint-byte

@antoinetoussaint-byteantoinetoussaint-byte commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Closes#287.

Summary

  • Adds the seventh agent kind, codefly:solution — the executor that scaffolds a solution, packages it (OCI), and renders its manifests into a gitops repo — following the codefly:provider precedent: dynamically installable, out of the application graph, operating on a codefly-agnostic solution spec.
  • Registry entry + proto enum (SOLUTION = 7) + IsSolution(); solution executor manifest schema (identity, services, api exposes/consumes, events, ui, needs, permissions, lifecycle) with canonical-bytes/digest for OCI packaging; and a Solution proto contract (Create/Update/Package/Render + GetSolutionInformation).
  • Manifest↔capability admission (Manifest.AdmitInformation): binds a runtime's advertised capabilities to the packaged, audited manifest — the advertised manifest digest must match and every advertised lifecycle op must have been declared. Mirrors provider's "runtime advertisement ⊆ packaged manifest" invariant, closing the drift/authorization gap where a host trusting one representation over the other would invoke an undeclared operation.

Review follow-ups (out of this PR by design)

Scope note

Core-side registry/proto/manifest slice for the kind. The end-to-end deploy tracer bullet (obin-ai/lodestar#17) and the CLI command group are separate.

Test plan

  • go build ./...
  • go test ./resources/ — registry exhaustiveness + path tests cover SOLUTION
  • go test ./solution/... — manifest load/validate, order-independent canonical digest, unknown-field/multi-doc rejection, identity + declaration validation (incl. bounded permission.resource, required services.name/ui.slot/needs.kind), descriptor-only solution, and AdmitInformation (digest match, subset-ok, undeclared-capability rejection)
  • go test ./agents/ ./policy/ ./standards/ green
  • codefly generate proto --local reproduces the committed generated code (unrelated plugin-version churn reverted)

Add the seventh agent kind, codefly:solution — the executor that
scaffolds a solution, packages it as an OCI artifact, and renders its
manifests into a gitops repository. Mirrors the codefly:provider
precedent: dynamically installable, stays out of the application graph,
and operates on a codefly-agnostic solution spec.
- Registry entry, proto enum value (SOLUTION = 7), and IsSolution().
- Solution executor manifest schema: identity, services, api
exposes/consumes, events, ui extensions, needs, permissions,
lifecycle — with canonical/digest support for OCI packaging.
- Solution proto contract: Create/Update/Package/Render plus
GetSolutionInformation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…on (#287)
Review findings from PR #288, in severity order.
D1 (the central invariant): the manifest Lifecycle and the proto
SolutionCapabilities were two unlinked descriptions of the same fact,
with nothing to catch drift — the provider precedent's admission check
(runtime advertisement ⊆ packaged manifest) was absent. Add
Manifest.AdmitInformation: the advertised manifest digest must equal the
packaged manifest's digest, and every advertised lifecycle capability
must have been declared in the packaged manifest. A runtime may
implement a subset but never advertise an operation the audited manifest
did not declare. This closes the silent authorization gap where a host
trusting one representation over the other would invoke an undeclared op.
D2: Permission.Resource was never validated — an empty or "*" resource
loaded clean. Require a bounded resource identifier.
Also harden secondary fields the schema left unvalidated (services.name,
ui.slot, needs.kind now required) and bound the created/updated/rendered
path result lists (max_items), matching the diagnostics fields' existing
defensive posture. Align sortedEventDeclarations with its siblings'
sort.Slice idiom.
D3 (host-enforceable per-method effect/network policy) and D4
(agents.Serve wiring so the contract is servable) are tracked as
follow-ups in #289 and #290; the proto now documents each RPC's effect
and states plainly that nothing enforces it yet, so "loads and
validates" is not mistaken for "enforces".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@antoinetoussaint-byte
antoinetoussaint-byte merged commit 186cef9 into mainAug 16, 2026
1 check passed
antoinetoussaint-byte added a commit that referenced this pull request Aug 16, 2026
… per-call ceiling
Review pushback was right: the previous refutations were dodges. Fixing the
real causes.
Finding 2 (no consumer): the host's single agent-connection factory is
agents/manager.loader (grpc.NewClient), and the connection it returns is
long-lived and reused across operations (AgentConn.GRPCConn). The interceptor
was built in a vacuum against neither fact. A ceiling baked in at dial time is
therefore the wrong shape — the ceiling belongs to the operation, which varies
per call over one shared connection. Carry it in the call context
(WithCeiling/CeilingFrom), install EnforcingClientInterceptor in the loader dial
options so it is genuinely wired (no-ops for non-Solution methods, safe on every
agent), and fail closed when a Solution RPC carries no ceiling.
Finding 4 (correlated axes): keeping two axes is only honest if they cannot go
incoherent. Add TestSolutionMethodPolicyAxesAreCoherent asserting registry
network iff registry effect, so an annotation like {OFFLINE, REGISTRY_WRITE}
(push while offline) fails the build instead of being silently accepted by the
ordered ceiling checks.
Finding 5 (reproducibility): verified empirically that committed v1.6.1 and
freshly regenerated v1.6.2 differ only in the header line — bodies byte-
identical — so matching #288's baseline is correct, not a Frankenstein file.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for freeto 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.

New agent kind: codefly:solution — registry entry, proto enum, manifest schema, proto service

1 participant

@antoinetoussaint-byte