/**
 * Device/user config keys — typed read/write over the three-layer store.
 *
 * One registry (`CONFIG_KEYS`) maps each CLI dotted name to where it lives:
 *   - user scope   → central `~/.agents/agents.yaml` under `config:` (syncs
 *                    fleet-wide via `agents repo push/pull`)
 *   - device scope → the per-device TRACKED doc
 *                    `~/.agents/devices/<name>/agents.yaml` under `config:` —
 *                    conflict-free by construction (each machine writes only
 *                    its own folder, and the churny auto-written pins no longer
 *                    share the file)
 *   - fleet layer  → central `~/.agents/agents.yaml` under
 *                    `fleet.defaults.config` — fleet-wide defaults written by
 *                    `agents devices config --fleet <key> <value>`
 *
 * Read order for a device-scope key: built-in default < fleet.defaults.config
 * < per-device config:. Names and non-secret values only (a secrets-bundle
 * NAME is fine; a credential never is).
 *
 * The device registry (`~/.agents/.history/devices/registry.json`) stays the
 * DISCOVERY cache (address, tailscale snapshot, reachability); the profile
 * fields config can override (ssh.*, platform, user) are overlaid onto it at
 * read time by `lib/devices/resolve-profile.ts`.
 *
 * Legacy stores (central `fleet.devices.<name>.config`, legacy auto-launch.json,
 * doc-level defaultBrowserProfile, pins in tracked docs) are folded into this
 * layout once by `lib/devices/config-migration.ts`, invoked on the first
 * read/write in a process — after migration there is ONE read path per layer,
 * no fallback branches.
 *
 * Unset always means today's behavior (the documented default).
 */
/** Which tier of the agents.yaml store a key lives in. */
export type ConfigScope = 'user' | 'device';
/**
 * For a device-scope key: WHO READS IT. Storage is still the three-layer
 * store (per-device doc / fleet.defaults.config); visibility only gates
 * whether a PEER may read or write the key.
 *
 * - `shared`  — a peer reads it (ssh.*, platform, role, caps), so any box
 *   may set it for any device. Lands in that device's tracked doc.
 * - `machine` — only the owning box ever reads it (scheduler, daemon, tmux,
 *   browser consent). Refused for a peer — run it on that box instead.
 */
export type ConfigVisibility = 'shared' | 'machine';
/** Value type of a config key — drives validation and `--json` rendering. */
export type ConfigType = 'string' | 'int' | 'bool' | 'string-list';
/** Fields every key carries, regardless of scope. */
interface ConfigKeySpecBase {
    /** CLI dotted name, e.g. `interactive.host`. */
    name: string;
    /** camelCase key under the YAML config block. */
    yamlKey: string;
    type: ConfigType;
    /** One-line description for help/list output. */
    description: string;
    /** The effective value when the key is unset (bool keys; drives the interactive menu's default). */
    defaultValue?: unknown;
    /** Extra validation beyond the type check; return an error string or null. */
    validate?: (value: unknown) => string | null;
}
/**
 * One known config key. A device-scope key MUST declare its `visibility`; a
 * user-scope key has none (it is fleet-wide by definition).
 */
export type ConfigKeySpec = (ConfigKeySpecBase & {
    scope: 'user';
    visibility?: never;
}) | (ConfigKeySpecBase & {
    scope: 'device';
    visibility: ConfigVisibility;
});
/** Which layer set a key's effective value (`default` = unset, built-in behavior). */
export type ConfigSource = 'user' | 'device' | 'fleet' | 'default';
/** A key with its resolved value and the layer that set it. */
export interface ConfigEntry {
    spec: ConfigKeySpec;
    /** The effective value, or undefined when unset (unset = default behavior). */
    value: unknown;
    /** Which layer set the effective value. */
    source: ConfigSource;
}
/** Options scoping a read/write: a specific device (default: this machine), or the fleet-defaults layer. */
export interface ConfigTarget {
    device?: string;
    /** Write/read the fleet-wide defaults layer (central fleet.defaults.config). */
    fleet?: boolean;
}
/** Roles a device can be marked with — see the `role` key below. */
declare const DEVICE_ROLES: readonly ["worker", "personal", "desktop"];
/** Which devices automatic placement may pick — see the `auto.pool` key below. */
declare const AUTO_POOL_MODES: readonly ["workers", "all"];
export declare const CONFIG_KEYS: readonly ConfigKeySpec[];
/** Look up a key spec by CLI dotted name, or throw listing the known keys. */
export declare function configKeySpec(name: string): ConfigKeySpec;
/**
 * Fold the legacy config/pins stores into the current layout, once per
 * process. A failure is loud but non-fatal — config reads must keep working,
 * and the next process retries the fold. Honors AGENTS_SKIP_MIGRATION=1, the
 * same gate bootstrap's runMigration uses (tests pin it so a fork never folds
 * the developer's real ~/.agents as a side effect).
 */
export declare function ensureDeviceConfigMigrated(): void;
/** The fleet-defaults config layer (central `fleet.defaults.config`; {} when unset). */
export declare function readFleetConfigDefaults(): Record<string, unknown>;
/**
 * The effective device-scope config block for `device`: fleet.defaults.config
 * overlaid with the per-device doc's config:. This is the single read path
 * post-migration — the profile resolver (`lib/devices/resolve-profile.ts`)
 * goes through here. Deliberately does NOT auto-trigger the migration: it
 * serves the hot dial/render paths. Sync and cheap (small local files).
 */
export declare function readDeviceConfigValues(device: string): Record<string, unknown>;
/** Get one config key's effective value and the layer that set it. */
export declare function getConfigValue(name: string, opts?: ConfigTarget): ConfigEntry;
/**
 * Async, non-blocking twin of {@link getConfigValue} for the daemon's tick paths
 * (PHNX-3695) — e.g. the watchdog tick reading `watchdog.enabled` every ~3min.
 * Same layer precedence (device doc → fleet defaults → default), but the
 * per-device doc READ is async. The user/fleet layers go through `readMeta`,
 * which serves from an mtime-stamped in-memory cache (≈ 2 stat syscalls on the
 * hot path, no file read), and `ensureDeviceConfigMigrated` is a one-shot no-op
 * after the first process-wide fold — neither blocks the loop meaningfully.
 */
export declare function getConfigValueAsync(name: string, opts?: ConfigTarget): Promise<ConfigEntry>;
/**
 * List every known key with its effective value and the layer that set it.
 *
 * Listing a PEER omits its machine-local keys rather than throwing — those
 * values live on that box and are unknowable from here, but a bulk listing
 * must not hard-fail. Asking for such a key by name still errors.
 */
export declare function listConfig(opts?: ConfigTarget): ConfigEntry[];
/** List user-scope config keys with their values. Used to show inherited settings
 * in per-device views without implying those keys are device-local. */
export declare function listUserConfig(): ConfigEntry[];
/**
 * Set a config key (validated). Device-scope keys target this machine unless
 * `opts.device` names a peer; `opts.fleet` writes the fleet-wide defaults layer
 * instead. User-scope keys reject `fleet` (they are already fleet-wide).
 */
export declare function setConfigValue(name: string, value: unknown, opts?: ConfigTarget): void;
/** Unset a config key — restores the next layer down (fleet default, then the
 * built-in default). No-op when already unset at that layer. */
export declare function unsetConfigValue(name: string, opts?: ConfigTarget): void;
/** A role an operator marked a device with (`agents devices role <name> <role>`). */
export type ConfiguredDeviceRole = (typeof DEVICE_ROLES)[number];
/** Which devices automatic placement may pick (`auto.pool`). */
export type AutoPoolMode = (typeof AUTO_POOL_MODES)[number];
/**
 * The role marked on one device, or undefined when the operator never marked it.
 *
 * Undefined is meaningful and is NOT the same as `worker`: an unmarked device is
 * eligible for automatic placement only while no device anywhere carries an
 * explicit `worker` mark (see {@link listConfiguredDeviceRoles}).
 */
export declare function configuredDeviceRole(name: string): ConfiguredDeviceRole | undefined;
/**
 * The role marked on THIS machine — the one running the CLI — or undefined when
 * it was never marked. Keyed off {@link machineId} (overridable via
 * AGENTS_SYNC_MACHINE_ID), so it matches the device's own config-folder key.
 *
 * The auth strategy reads this: a headed device (`personal` or `desktop`, see
 * {@link isHeadedDeviceRole}) holds a real per-version login and MUST
 * authenticate from it for EVERY run, interactive or headless; only a `worker`
 * uses the file-based setup-token (RUSH-2395). `undefined` is treated as
 * non-headed (worker-equivalent) by that gate — an unmarked box has no login to
 * defer to.
 */
export declare function selfConfiguredDeviceRole(): ConfiguredDeviceRole | undefined;
/**
 * A "headed" device — one with an interactive desktop login, so it authenticates
 * from its own per-version Claude login (which carries the `user:profile` scope
 * the usage endpoint needs) rather than the headless file setup-token. Both
 * `personal` (the box you sit at) and `desktop` (a headed always-on box like a
 * Mac mini) qualify; a `worker` and an unmarked box do NOT. This is the single
 * predicate the auth-bucket sites read, so `personal` and `desktop` never drift
 * apart (claude adapter, routine spawn env, `agents view` usage login).
 */
export declare function isHeadedDeviceRole(role: ConfiguredDeviceRole | undefined): boolean;
/** Mark a device's role fleet-wide; `undefined` clears the mark. */
export declare function setConfiguredDeviceRole(name: string, role: ConfiguredDeviceRole | undefined): void;
/**
 * Devices whose OWN config pins one of the browser profile keys to `profile`.
 *
 * Used by `profiles rename` to warn rather than silently leave a peer pointing at
 * a name that no longer exists. Deliberately read-only: rewriting another
 * machine's device doc from here would be a cross-machine mutation nobody asked
 * for, and the pin may well be correct there (a local profile of the same name).
 */
export declare function devicesPinningBrowserProfile(profile: string): Array<{
    device: string;
    key: 'browser.profile' | 'browser.viewer';
}>;
/**
 * Every device with an effective role, keyed by device name. Layers like every
 * other device-scope key: the fleet default (central fleet.defaults.config)
 * applies fleet-wide and the per-device doc wins on conflict. `roster` (the
 * registered device names) lets a fleet default reach devices that have no doc
 * of their own; without it only devices with docs are considered — so a
 * fleet-wide `role` default would silently miss a doc-less device and drop it
 * from the worker allowlist. Mirrors {@link loadAutoLaunchPreferences}.
 */
export declare function listConfiguredDeviceRoles(roster?: string[]): Record<string, ConfiguredDeviceRole>;
/** The configured automatic-placement pool mode. Unset means `workers`. */
export declare function autoPoolMode(): AutoPoolMode;
/**
 * A device's auto-launch flags, read by the automatic-placement pool
 * (`filterAutoPool` drops `enabled: false`; `pickBestDevice` boosts
 * `preferred: true` — see `lib/devices/pool.ts`) and by the menu-bar snapshot.
 */
export interface AutoLaunchPreference {
    enabled?: boolean;
    preferred?: boolean;
}
/** True if the device is enabled for auto-launch. Unset defaults to true. */
export declare function isAutoLaunchEnabled(name: string): boolean;
/** Set whether a device is enabled for auto-launch. Setting the default
 * (enabled) removes the key to keep the doc minimal. */
export declare function setAutoLaunchEnabled(name: string, enabled: boolean): void;
/** True if the device is preferred for auto-launch ranking. */
export declare function isAutoLaunchPreferred(name: string): boolean;
/** Set whether a device is preferred for auto-launch. Setting the default
 * (not preferred) removes the key to keep the doc minimal. */
export declare function setAutoLaunchPreferred(name: string, preferred: boolean): void;
/**
 * Every device's effective auto-launch flags, keyed by device name — the shape
 * the menu-bar snapshot consumes. Layers like every other device-scope key: the
 * fleet default (central fleet.defaults.config) applies fleet-wide and the
 * per-device doc wins on conflict. `roster` (the registered device names) lets
 * a fleet default reach devices that have no doc of their own; without it only
 * devices with docs are listed.
 */
export declare function loadAutoLaunchPreferences(roster?: string[]): Record<string, AutoLaunchPreference>;
/** True unless this machine's config disables the routines scheduler. */
export declare function isSchedulerEnabled(): boolean;
/**
 * Throw when the routines scheduler is disabled on this machine, naming the
 * setting and the fix. The single message every scheduler-start surface
 * (auto-start on `routines add`, manual `routines start`, the daemon's own
 * scheduler init) refuses with.
 */
export declare function assertSchedulerEnabled(): void;
/** True only when this machine explicitly enables the managed tmux wrap. */
export declare function isTmuxEnabled(): boolean;
/** True unless this machine's config disables the daemon outright (top-level kill switch). */
export declare function isDaemonEnabled(): boolean;
/**
 * Throw when the daemon is disabled on this machine, naming the setting and
 * the fix. Every AUTO-start surface (routines add/start/catchup/webhook,
 * monitors add, `ensureDaemonStarted`) refuses with this before calling
 * `startDaemon()`. `agents daemon start` is the deliberate override and does
 * NOT call this — disable only blocks auto-start, mirroring `systemctl disable`.
 */
export declare function assertDaemonEnabled(): void;
/**
 * Idle window (ms) the browser-task reaper (`browser/hygiene.ts`) uses on THIS
 * machine, or `null` when idle reaping is off (`browser.task-idle-minutes=0`)
 * — session-dead reaping is unaffected either way. Unset means the default 30
 * minutes. Read by the daemon's periodic tick and, as the fallback when a
 * caller omits `--idle-minutes`, by the `gc` IPC action.
 */
/** Async so the daemon's browser-task-reap tick reads the config off the shared event loop (PHNX-3695). */
export declare function resolveBrowserTaskIdleMs(): Promise<number | null>;
/**
 * Read the effective `agents.max-concurrent` cap for each named device (fleet
 * defaults layered under the per-device doc; no SSH). Devices without a cap
 * are omitted — uncapped is the default. Used as an input to host ranking
 * (teams placement, AGI EXT auto-launch), never as a remote probe.
 */
export declare function readMaxConcurrentCaps(devices: string[]): Record<string, number>;
export {};
