/** Hard cap on the SKILL.md size we'll read. Skills longer than this * almost always indicate a misconfigured doc dropped into the skills * dir; we ignore the body to keep injection cheap and audit-able. */ export declare const MAX_SKILL_BODY_CHARS = 32000; /** Tier-1 description hard cap. Long descriptions inflate the system * prompt budget for every turn; truncate with "…" so the operator * immediately notices when the cap was hit. */ export declare const MAX_DESCRIPTION_CHARS = 400; /** Maximum skills we'll inject into a single system prompt block. * Above this, the agent is better served by a `/skill list` overview * + on-demand `read_skill` than a wall of text. */ export declare const MAX_INJECTED_SKILLS = 32; export interface SkillMeta { name: string; description: string; /** Source: 'workspace' wins shadowing over 'builtin' with the same name. */ source: 'workspace' | 'builtin'; /** Absolute path of the skill's directory (parent of SKILL.md). */ dir: string; /** When true, the body is auto-injected after the tier-1 summary * rather than waiting for a read_skill call. Use sparingly — every * `always: true` skill burns tokens on every turn. */ always: boolean; /** Frontmatter `metadata.agim.requires.bins` declared dependencies * (CLI executables in PATH). */ requiresBins: string[]; /** Frontmatter `metadata.agim.requires.env` declared dependencies * (environment variables that must be non-empty). */ requiresEnv: string[]; /** True iff every `requires.bins` is on PATH AND every `requires.env` * is non-empty. Unavailable skills are still listed (with a marker) * so the agent can ask the operator to install the missing piece. */ available: boolean; /** Operator-facing reason when `available=false`. */ unavailableReason?: string; /** Frontmatter `origin:` value, when present. ECC pack skills declare * `origin: ECC`; operators can use this to bucket / filter their own * packs. Optional — most operator-authored skills omit it. */ origin?: string; } export type SkillsMode = 'auto' | 'agim-only' | 'custom'; /** * Resolve the ordered list of skill discovery roots (highest priority * first). The agim-owned `workspaceSkillsDir()` is ALWAYS at index 0 * — it's the write target and must shadow same-named entries in * inherited roots so operator-installed skills can override defaults. * * Modes: * - `auto` (default): workspace + ~/.claude/skills + ~/.config/opencode/skills * + ~/.codex/skills. Reflects the typical "I installed all three * CLI agents and they share via symlink" layout — agim sees * 100+ shared skills out of the box without extra config. * Honors AGIM_SKILLS_EXTRA_ROOTS for adding more. * - `agim-only`: only the workspace dir. For deployments that want * isolation from per-user CLI agent directories. * - `custom`: workspace + AGIM_SKILLS_ROOTS (explicit operator list). * * The builtin dir is NOT included here — it's tier-0 (bundled with agim) * and scanned separately as a last resort in doScan(). */ export declare function resolveSkillsRoots(): string[]; /** Public describe-only API for the web admin / diagnostics. Returns * a snapshot of the active mode + the roots that will be scanned. */ export declare function describeSkillsConfig(): { mode: SkillsMode; writeRoot: string; readRoots: string[]; builtinRoot: string; }; /** Force a fresh disk scan on next call. Returned by /skill refresh. */ export declare function invalidateSkillsCache(): void; /** * Write (create-or-overwrite) a workspace SKILL.md (P1 web editor). * * - Lands at //SKILL.md (operator path, * not builtin) so subsequent scans pick it up and it shadows any * same-named builtin. * - name is sanitized to safe filesystem chars (no '..', no * leading dots, no slashes). Returns null on invalid name. * - Body MUST already include the YAML frontmatter; we validate * it parses + has a description before writing so the editor * can't ship a broken SKILL.md. Returns the parsed SkillMeta * on success. * - Invalidates the cache so listSkills() picks up the new file * on next call. */ export declare function writeSkillFile(name: string, body: string): SkillMeta | null; /** * Delete a workspace skill. Builtin (bundled) skills can't be * deleted — operators have to shadow them with a workspace entry * (which writeSkillFile does for them). Returns true iff a file * was actually unlinked. */ export declare function deleteSkill(name: string): boolean; /** Read-only access to the loaded skill list. Triggers a scan on first * call or when the cache has expired. Never throws — disk errors yield * the partial list discovered up to that point. */ export declare function listSkills(): SkillMeta[]; /** Look up one skill by name (case-insensitive). Returns null when * unknown; caller decides whether to surface "no such skill" to the * agent or the operator. */ export declare function getSkillByName(name: string): SkillMeta | null; /** Read the full SKILL.md body for a known skill. Returns null on * unknown name OR read failure. Honors the MAX_SKILL_BODY_CHARS cap; * oversize files come back truncated with a `[truncated …]` footer. */ export declare function readSkillBody(name: string): string | null; /** * v1.2.151 — Resolve the active ECC top-pick set. Operators can override * via `AGIM_SKILLS_ECC_PICKS=name1,name2,...`. An empty or unset value * falls back to the default 20-name list. Validation is intentionally * forgiving: unknown names pass through (they just become no-ops when * the named skill isn't installed). */ export declare function resolveEccTopPicks(): ReadonlySet; /** * v1.2.151 — ECC remainder injection policy. Default `on` emits the * cluster block. `off` suppresses it entirely (token-saving for ops * who only want the recommended picks). A comma-list value flips to * "allowlist" mode: only remainder skills in the list are emitted. */ type EccRemainderMode = { mode: 'on'; } | { mode: 'off'; } | { mode: 'allowlist'; names: Set; }; export declare function resolveEccRemainderMode(): EccRemainderMode; export declare function injectionOverridePath(): string; /** Read the override file. Returns the trimmed body, or null when the * file is missing / empty / unreadable. Never throws. */ export declare function readInjectionOverride(): string | null; /** Write (or replace) the override file. The caller is responsible for * authorization — this is a thin filesystem helper. Returns true on * success, false on any disk error. */ export declare function writeInjectionOverride(body: string): boolean; /** Delete the override file. Returns true when a file was actually * removed (or already gone), false on filesystem error. */ export declare function deleteInjectionOverride(): boolean; /** * v1.2.149 — Rank a skill into one of four buckets for system-prompt * injection. Lower rank wins (fills the visible 32 first). Within a * bucket, alphabetical order. Buckets: * * 0 — agim framework skills (name starts with `agim-`). Always relevant * to anyone running agim; should never miss the cap. * 1 — non-ECC builtin skills (the small in-tree agim pack: github, * image-generation, long-goal, my, skill-creator, summarize, tmux, * weather). Curated by us specifically for the framework. * 2 — ECC recommended (the curated list above). Pinned harness / dev * methodology essentials from the ECC pack. * 3 — Everything else: ECC remainder (210+) and operator workspace * skills (the operator's business domain — fin-data, ash, etc.). * Reachable via read_skill on description match; not strapped to * the front of the prompt. * * Workspace skills land in 3 rather than 1 because operator-authored * content varies wildly per install — pinning them all means a finance * operator's 60 fin-data skills push out an unrelated operator's 60 * homelab skills. Both belong in the on-demand pool, not the cap. */ export declare function rankSkillBucket(s: SkillMeta): number; /** * v1.2.150 — A prefix-based skill cluster. Many skills sharing a name * prefix (`fin-data-aspd-*`, `white-pig-*`, …) get collapsed into one * block: title + name list + brief trigger hint. The LLM still sees * every skill name, just not every full description; it can call * `read_skill('exact-name')` for granular content. */ export interface SkillCluster { /** The shared prefix, e.g. "fin-data-aspd" or "white-pig". */ prefix: string; /** Skill names in the cluster, alphabetically sorted. */ names: string[]; /** One-line trigger summary derived from member descriptions * (best effort). Empty when descriptions are unhelpful. */ triggerHint: string; } /** * v1.2.150 — Pure helper: group `skills` into prefix-based clusters. * * Algorithm: * 1. Group by first dash-segment (`fin-data-aspd-*` → key `fin`). * 2. For groups of size ≥ minSize, try refining to TWO segments * (`fin-data-*`). If at least 2 two-segment sub-groups themselves * reach minSize, emit each sub-group as a cluster and the leftover * single-segment-only members as a fallback `-*` cluster. * 3. Sub-clustering attempts also at THREE segments before bottoming * out, so `fin-data-aspd-*` peels off `fin-data-aspd` instead of * drowning in a generic `fin-data`. * 4. Skills that don't land in any cluster (≤ minSize − 1 with their * prefix peers) are returned as singletons; the caller renders * them as individual rows. * * Pure / deterministic — same input always yields same output. */ export declare function clusterSkills(skills: ReadonlyArray, minSize?: number): { clusters: SkillCluster[]; singletons: SkillMeta[]; }; /** * v1.2.151 — Build the auto-generated tier-1 block (no header, no * always-on bodies — caller wraps). Separated so the SPA editor can * preview "what would auto produce right now" via the admin API. * * Bucket render order: * 0 framework → 1 builtin → **3 workspace** → 2 ECC picks → 4 ECC remainder * * Operator-installed workspace skills out-rank ECC pinned picks because * they are the strongest "I want this" signal. ECC picks (curated * harness vocabulary) come right after so the LLM still has them * within reach. ECC remainder lives at the bottom as the on-demand * pool. * * Buckets 0/1/2/3 all emit full rows (renderSkillRow). Only bucket 4 * (ECC remainder) clusters — and even then, the cluster path can be * disabled or scoped via `AGIM_SKILLS_INJECT_ECC_REMAINDER`. */ export declare function buildAutoInjectionBlock(all: ReadonlyArray): string; export declare function buildSkillsSummary(): string; export {}; //# sourceMappingURL=loader.d.ts.map