/** 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;
}
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 IMHUB_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 + IMHUB_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 <workspaceSkillsDir>/<name>/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;
/**
 * Build the tier-1 system-prompt block. Injected once per turn by the
 * router. Returns '' when no skills are configured (router drops empty
 * blocks). Bounded to MAX_INJECTED_SKILLS rows; above the cap we keep
 * the first N alphabetically and append a one-line "+ N more (call
 * /skill list to see)" note.
 *
 * Format (kept close to nanobot's so models trained on its docs feel
 * at home):
 *
 *   [agim skills available — read full body with mcp__imhub__read_skill(name)]
 *   - skill-a: one-line description
 *   - skill-b: one-line description (unavailable: missing bin `foo`)
 *   - skill-c: one-line description
 *   …
 */
export declare function buildSkillsSummary(): string;
//# sourceMappingURL=loader.d.ts.map