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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! The shipped `Agent` catalog as one owning artifact.
//!
//! `manifests/base/agents.yaml` is the authored, kubectl-applied source of
//! truth for the deployed `Agent` custom resources (see that file's own
//! header, and `docs/reference/declarative-catalog.md`). Before this crate,
//! every consumer that needed the shipped catalog's *content* — the
//! installer, and three separate test suites — addressed the tree path by
//! hand and re-parsed it, and one of those consumers (the harness test
//! support) even carried its own partial copy of the `Agent` schema. A
//! catalog edit could then pass two of those readers and silently drift
//! against the third.
//!
//! This crate embeds the shipped file at compile time and exposes it through
//! one typed decode path, [`shipped`], into `polyc_controller::Agent` — the
//! same type the apiserver and the reconciler use. Every other Rust
//! consumer of the catalog's *content* goes through this crate; the
//! installer's raw `kubectl apply -f` (which applies the file rather than
//! parsing it) instead names the tree path via [`MANIFEST_PATH`].
//!
//! Parsing itself does not deep-validate references (a dangling
//! `toolsEnabled` or `canHandoffTo` entry is a reconciler `.status` concern,
//! not a decode concern) — see `polyc_controller::agent`'s module doc.
use Agent;
use Deserialize as _;
/// The catalog's tree path, relative to the repository root.
///
/// The single string every path-addressing consumer (the CLI installer, and
/// any test asserting on the applied path) should use instead of a locally
/// hand-copied literal. This is a path for tools that *apply* the manifest
/// (`kubectl apply -f`); this crate's own [`shipped`] reads the file's
/// *content* via a compiled-in [`include_str!`], not this constant, so a
/// decode never depends on the process's working directory.
pub const MANIFEST_PATH: &str = "manifests/base/agents.yaml";
/// The shipped catalog's raw YAML, embedded at compile time.
///
/// `agents.yaml` at this crate's root is a symlink to
/// `manifests/base/agents.yaml`, so the repository keeps one authored file.
/// The include must stay INSIDE the crate root: `cargo publish` packages only
/// the crate directory, and it follows the symlink to copy the content. An
/// include that reached `../../../manifests/...` built in the workspace and
/// failed to build from the published tarball (the 2026.8.3 release run).
const RAW: &str = include_str!;
/// A failure decoding the shipped catalog.
/// Decode the shipped `Agent` catalog into its typed form.
///
/// # Errors
///
/// Returns [`CatalogError`] when a document fails to parse as an `Agent`, or
/// when a parsed `Agent` has no `metadata.name`.
/// The shipped agent named `name`, if the catalog ships one.
/// `agent`'s `metadata.name`.
///
/// [`shipped`] already refuses to decode any document missing
/// `metadata.name` (see [`CatalogError::MissingName`]), so every `Agent` that
/// reaches a caller through this crate is named — callers that hold an
/// `Agent` produced by [`shipped`] should use this instead of re-deriving
/// their own fallback (a silent `unwrap_or_default` would mask that
/// invariant weakening instead of failing loudly).
///
/// # Panics
///
/// Panics if `agent.metadata.name` is `None` — meaning `agent` did not come
/// from [`shipped`], since that path guarantees a name.