@karmaniverous/jeeves-scripts-core
    Preparing search index...

    Function loadConfig

    • Load, validate and cache the instance config. Subsequent calls (without resetConfig) return the cached value regardless of options.

      Parameters

      Returns {
          $schema?: string;
          instance: { baseDir: string; name: string };
          integrations: {
              gh: {
                  account?: string;
                  bin?: string;
                  botUser?: string;
                  configDir?: string;
              };
              gog: { bin?: string };
              jira: {
                  apiTokenPath?: string;
                  boardId?: number;
                  email?: string;
                  fieldsFilename?: string;
                  maxHistory?: number;
                  siteUrl?: string;
              };
              linear: { configPath?: string; maxHistory?: number };
              notion: { version?: string };
              qdrant: { apiUrl?: string; serviceName?: string };
              x: { accounts: Record<string, { relativePath?: string; silo?: string }> };
          };
          jobs: Record<
              string,
              {
                  account?: string;
                  args?: string[];
                  contextThreshold?: number;
                  enabled?: boolean;
                  env?: Record<string, string>;
                  excludedKeys?: string[];
                  extraDirs?: string[];
                  files?: { source: string; target: string }[];
                  idleMinutes?: number;
                  on_failure?: string | null;
                  owners?: {
                      exclude?: string[];
                      include?: string[];
                      owner: string;
                      ruleset?: boolean;
                      type: "user" | "org";
                  }[];
                  ruleset?: {
                      enforcement: string;
                      name: string;
                      rules: { type: string; [key: string]: unknown }[];
                      target: string;
                      [key: string]: unknown;
                  };
                  schedule?: string
                  | Record<string, unknown>;
                  silo?: string;
                  taskFile?: string;
                  timeout_seconds?: number;
              },
          >;
          library: {
              mirrors: {
                  adopt: boolean;
                  dest: string;
                  exclude: string[];
                  id: string;
                  minRatio: number;
                  ref: string;
                  repo: string;
                  siteLinks?: { pattern: string; target: string };
                  subdir: string;
              }[];
          };
          local?: unknown;
          paths: {
              configDir?: string;
              contentDir?: string;
              credentialsDir?: string;
              gogHome?: string;
              scriptsDir?: string;
              stateDir?: string;
              tokenMetricsDir?: string;
          };
          people: Record<
              string,
              {
                  accounts?: { account: string; channel: string; id: string }[];
                  emails?: string[];
                  name: string;
              },
          >;
          pipeline?: {
              accounts: {
                  calendar?: { tokenFile: string }
                  | { serviceAccount: "auto" };
                  email: string;
                  emailPolling: boolean;
                  folders?: string[];
                  imap?: {
                      host: string;
                      password: { secretRef: string };
                      port: number;
                      tls: boolean;
                      user: string;
                  };
                  reportOnly?: boolean;
                  type: "gmail"
                  | "imap";
              }[];
              buckets: {
                  domains: { bucket: string; pattern: string }[];
                  priority: string[];
              };
              emailConfig: {
                  backfill?: {
                      accounts: string[];
                      lookbackDays: number;
                      windowDays: number;
                  };
                  digest: { slackChannelId: string };
                  meetings?: { archive: boolean };
                  reportOnly: boolean;
                  respond?: {
                      allowedSenders: string[];
                      dryRun?: boolean;
                      label: string;
                      mailbox: string;
                      maxPerRun: number;
                      maxRepliesPerThreadPerHour: number;
                      slackMirror: boolean;
                  };
              };
              googleDrive?: unknown;
              refs: Record<string, string>;
          };
          punchList?: {
              cursorFile?: string;
              dir: string;
              inboxDir?: string;
              inputRoots?: string[];
              installMap: Record<string, { component: string; packageJson: string }[]>;
              lockFile?: string;
              pendingFile?: string;
              retentionDays: number;
              scriptsRepo: { clone: string; repo: string };
              slack: { account: string; channel: string; pinnedTs?: string };
              specPath?: string;
              timeZone: string;
          };
          siloRouting: {
              defaultBasePath?: string;
              silos: Record<
                  string,
                  {
                      basePath: string;
                      emailDomains?: string[];
                      githubOrgs?: (string | { githubOrg: string; relativePath: string })[];
                      jira?: boolean;
                      linear?: boolean;
                      slackWorkspaces?: string[];
                  },
              >;
          };
          skillReview?: {
              budgetAlertPercent: number;
              outputDir?: string;
              reportAccount: string;
              reportChannel: string;
              serverKey: string;
              timezone: string;
          };
          slack: {
              backfillBudgetSeconds: number;
              channelMeta?: {
                  activityDays: number;
                  descriptionMaxChars: number;
                  excludeChannels: string[];
                  maxChannels: number;
                  outputDir?: string;
                  pathRoots: Record<string, string>;
                  relativeRoot?: string;
                  reportAccount?: string;
                  reportChannel?: string;
                  reportTextAccounts?: string[];
                  serverKey: string;
                  sweepPatterns: string[];
                  timezone: string;
                  topicMaxChars: number;
                  updateDescriptions: boolean;
                  updateTopics: boolean;
              };
              channels: Record<string, { homeDir?: string; project?: string }>;
              newChannelLookbackDays?: number;
          };
          transcripts?: {
              libraryDir?: string;
              scratchDir?: string;
              userAgent?: string;
          };
      }

      • Optional$schema?: string

        JSON Schema reference for editor completion.

      • instance: { baseDir: string; name: string }

        Instance identity and base directory.

        • baseDir: string

          Base directory every default path derives from.

        • name: string

          Instance name (e.g. acme).

      • integrations: {
            gh: {
                account?: string;
                bin?: string;
                botUser?: string;
                configDir?: string;
            };
            gog: { bin?: string };
            jira: {
                apiTokenPath?: string;
                boardId?: number;
                email?: string;
                fieldsFilename?: string;
                maxHistory?: number;
                siteUrl?: string;
            };
            linear: { configPath?: string; maxHistory?: number };
            notion: { version?: string };
            qdrant: { apiUrl?: string; serviceName?: string };
            x: { accounts: Record<string, { relativePath?: string; silo?: string }> };
        }

        External tools and services.

        • gh: { account?: string; bin?: string; botUser?: string; configDir?: string }

          GitHub CLI.

          • Optionalaccount?: string

            GitHub user or org whose repos the github domain syncs.

          • Optionalbin?: string

            Path to the gh executable. Default: gh on PATH.

          • OptionalbotUser?: string

            GitHub bot user that acts for the instance.

          • OptionalconfigDir?: string

            GH_CONFIG_DIR for gh (auth, hosts). Default: {configDir}/gh-cli.

        • gog: { bin?: string }

          gog.

          • Optionalbin?: string

            Path to the gog executable. Default: gog on PATH.

        • jira: {
              apiTokenPath?: string;
              boardId?: number;
              email?: string;
              fieldsFilename?: string;
              maxHistory?: number;
              siteUrl?: string;
          }

          Jira.

          • OptionalapiTokenPath?: string

            Path to the file holding the API token. Default: under credentialsDir.

          • OptionalboardId?: number

            Agile board id the backlog jobs work on.

          • Optionalemail?: string

            Account email the API token belongs to.

          • OptionalfieldsFilename?: string

            File name of the cached field map at the Jira domain root.

          • OptionalmaxHistory?: number

            Maximum history entries kept per Jira entity file.

          • OptionalsiteUrl?: string

            Jira site base URL.

        • linear: { configPath?: string; maxHistory?: number }

          Linear.

          • OptionalconfigPath?: string

            Path to the Linear credential file. Default: under credentialsDir.

          • OptionalmaxHistory?: number

            Maximum history entries kept per Linear entity file.

        • notion: { version?: string }

          Notion.

          • Optionalversion?: string

            Notion-Version API header value.

        • qdrant: { apiUrl?: string; serviceName?: string }

          Qdrant.

          • OptionalapiUrl?: string

            Qdrant HTTP API base URL. Default: the watcher's vectorStore.url ({configDir}/jeeves-watcher/config.json), else http://localhost:6333. Set it only when no watcher config names the Qdrant this instance uses.

          • OptionalserviceName?: string

            OS service name the health check restarts (case-sensitive on Windows).

        • x: { accounts: Record<string, { relativePath?: string; silo?: string }> }

          X / Twitter.

          • accounts: Record<string, { relativePath?: string; silo?: string }>

            Accounts by handle.

      • jobs: Record<
            string,
            {
                account?: string;
                args?: string[];
                contextThreshold?: number;
                enabled?: boolean;
                env?: Record<string, string>;
                excludedKeys?: string[];
                extraDirs?: string[];
                files?: { source: string; target: string }[];
                idleMinutes?: number;
                on_failure?: string | null;
                owners?: {
                    exclude?: string[];
                    include?: string[];
                    owner: string;
                    ruleset?: boolean;
                    type: "user" | "org";
                }[];
                ruleset?: {
                    enforcement: string;
                    name: string;
                    rules: { type: string; [key: string]: unknown }[];
                    target: string;
                    [key: string]: unknown;
                };
                schedule?: string
                | Record<string, unknown>;
                silo?: string;
                taskFile?: string;
                timeout_seconds?: number;
            },
        >

        Per-job deltas.

      • library: {
            mirrors: {
                adopt: boolean;
                dest: string;
                exclude: string[];
                id: string;
                minRatio: number;
                ref: string;
                repo: string;
                siteLinks?: { pattern: string; target: string };
                subdir: string;
            }[];
        }

        Public repo subdirectories mirrored into the content tree (library-sync-mirrors).

        • mirrors: {
              adopt: boolean;
              dest: string;
              exclude: string[];
              id: string;
              minRatio: number;
              ref: string;
              repo: string;
              siteLinks?: { pattern: string; target: string };
              subdir: string;
          }[]

          The mirrors, run in order (default none: library-sync-mirrors skips).

      • Optionallocal?: unknown

        The instance's own block: core never reads it; the instance plugin's configSchema validates it and localConfig() returns it.

      • paths: {
            configDir?: string;
            contentDir?: string;
            credentialsDir?: string;
            gogHome?: string;
            scriptsDir?: string;
            stateDir?: string;
            tokenMetricsDir?: string;
        }

        Path overrides.

        • OptionalconfigDir?: string

          Config directory. Default: {baseDir}/config.

        • OptionalcontentDir?: string

          Content directory, the default silo's base path. Default: {baseDir}/content.

        • OptionalcredentialsDir?: string

          Credential files. Default: {configDir}/credentials.

        • OptionalgogHome?: string

          gog home (service-account keys, OAuth client credentials, file keyring). Its own key because it does not sit under configDir on every instance (some keep it under their credentials dir). Default: {configDir}/gogcli; GOG_HOME wins.

        • OptionalscriptsDir?: string

          The instance repo. Default: {baseDir}/jeeves-scripts.

        • OptionalstateDir?: string

          Service state. Default: {baseDir}/state.

        • OptionaltokenMetricsDir?: string

          Token metrics output. Default: under stateDir; TOKEN_METRICS_DIR wins.

      • people: Record<
            string,
            {
                accounts?: { account: string; channel: string; id: string }[];
                emails?: string[];
                name: string;
            },
        >

        Which accounts and emails belong to one person (Decision 34).

      • Optionalpipeline?: {
            accounts: {
                calendar?: { tokenFile: string } | { serviceAccount: "auto" };
                email: string;
                emailPolling: boolean;
                folders?: string[];
                imap?: {
                    host: string;
                    password: { secretRef: string };
                    port: number;
                    tls: boolean;
                    user: string;
                };
                reportOnly?: boolean;
                type: "gmail"
                | "imap";
            }[];
            buckets: {
                domains: { bucket: string; pattern: string }[];
                priority: string[];
            };
            emailConfig: {
                backfill?: {
                    accounts: string[];
                    lookbackDays: number;
                    windowDays: number;
                };
                digest: { slackChannelId: string };
                meetings?: { archive: boolean };
                reportOnly: boolean;
                respond?: {
                    allowedSenders: string[];
                    dryRun?: boolean;
                    label: string;
                    mailbox: string;
                    maxPerRun: number;
                    maxRepliesPerThreadPerHour: number;
                    slackMirror: boolean;
                };
            };
            googleDrive?: unknown;
            refs: Record<string, string>;
        }

        Mail, calendar and refs (the template's pipeline-config.json).

        • accounts: {
              calendar?: { tokenFile: string } | { serviceAccount: "auto" };
              email: string;
              emailPolling: boolean;
              folders?: string[];
              imap?: {
                  host: string;
                  password: { secretRef: string };
                  port: number;
                  tls: boolean;
                  user: string;
              };
              reportOnly?: boolean;
              type: "gmail"
              | "imap";
          }[]

          Mail and calendar accounts.

        • buckets: { domains: { bucket: string; pattern: string }[]; priority: string[] }

          Mail bucket routing.

          • domains: { bucket: string; pattern: string }[]

            Domain rules, first match wins.

          • priority: string[]

            Bucket names, highest priority first.

        • emailConfig: {
              backfill?: {
                  accounts: string[];
                  lookbackDays: number;
                  windowDays: number;
              };
              digest: { slackChannelId: string };
              meetings?: { archive: boolean };
              reportOnly: boolean;
              respond?: {
                  allowedSenders: string[];
                  dryRun?: boolean;
                  label: string;
                  mailbox: string;
                  maxPerRun: number;
                  maxRepliesPerThreadPerHour: number;
                  slackMirror: boolean;
              };
          }

          Email pipeline settings.

          • Optionalbackfill?: { accounts: string[]; lookbackDays: number; windowDays: number }

            Paced historical backfill.

            • accounts: string[]

              Gmail accounts to backfill.

            • lookbackDays: number

              How far back from now to walk, in days.

            • windowDays: number

              Days searched per run, per account.

          • digest: { slackChannelId: string }

            Email digest.

            • slackChannelId: string

              Slack channel the email digest posts to.

          • Optionalmeetings?: { archive: boolean }

            Actions on meeting source emails.

            • archive: boolean

              Archive the source email out of INBOX after packaging.

          • reportOnly: boolean

            Report Gmail changes (labels, archive) without making them, for every account. accounts[].reportOnly opts a single account in.

          • Optionalrespond?: {
                allowedSenders: string[];
                dryRun?: boolean;
                label: string;
                mailbox: string;
                maxPerRun: number;
                maxRepliesPerThreadPerHour: number;
                slackMirror: boolean;
            }

            Assistant-mailbox auto-reply (email-respond).

            • allowedSenders: string[]

              Senders allowed to trigger a reply: exact addresses or *@example.com (that domain; not a consumer provider). Must not list mailbox exactly; a pattern covering it never lets it qualify.

            • OptionaldryRun?: boolean

              Discovery + qualification only: no dispatch, no send, no state writes.

            • label: string

              Gmail label applied to a thread after a successful reply.

            • mailbox: string

              The mailbox that receives and replies to mail.

            • maxPerRun: number

              Messages processed per run, oldest first (default 3).

            • maxRepliesPerThreadPerHour: number

              Per-thread reply rate limit (default 3/hour).

            • slackMirror: boolean

              Mirror each sent reply to Slack (the sender's DM, or a channel the email asked for). Needs the users:read.email bot scope. Default off.

        • OptionalgoogleDrive?: unknown

          Google Drive sync block, kept raw here: the google-drive domain validates it, so a mistake in it fails only the Drive job, never every job that loads this config.

        • refs: Record<string, string>

          Named references (Slack channels, Notion ids, paths) by dotted key.

      • OptionalpunchList?: {
            cursorFile?: string;
            dir: string;
            inboxDir?: string;
            inputRoots?: string[];
            installMap: Record<string, { component: string; packageJson: string }[]>;
            lockFile?: string;
            pendingFile?: string;
            retentionDays: number;
            scriptsRepo: { clone: string; repo: string };
            slack: { account: string; channel: string; pinnedTs?: string };
            specPath?: string;
            timeZone: string;
        }

        The instance's daily punch list (punch-list-*); absent: both runnables skip.

        • OptionalcursorFile?: string

          Harvest window cursor (default {stateDir}/punch-list/harvest-cursor.json).

        • dir: string

          Directory of the daily files, harvest/ records and an optional TASK.md.

        • OptionalinboxDir?: string

          Where the harvest worker writes its report (default {stateDir}/punch-list/inbox).

        • OptionalinputRoots?: string[]

          What the harvester's pre-check watches for new input (default: the default silo's email, slack, meetings and google-drive, plus {stateDir}/jeeves-watcher/issues.json). {home} and {npmGlobal} are expanded.

        • installMap: Record<string, { component: string; packageJson: string }[]>

          Versioned repos (owner/name) scanned for milestones, with where each component installs (default none).

        • OptionallockFile?: string

          Lock held by every runnable write (default {stateDir}/punch-list/punch-list.lock).

        • OptionalpendingFile?: string

          Notifications not yet posted (default {stateDir}/punch-list/status-pending.json).

        • retentionDays: number

          Days a finished entry stays before it is left off the next day's file (default 30).

        • scriptsRepo: { clone: string; repo: string }

          This instance's scripts repo: unversioned, so Done means a merged PR.

          • clone: string

            The deployed clone; a PR is installed once its merge commit is in its HEAD.

          • repo: string

            owner/name.

        • slack: { account: string; channel: string; pinnedTs?: string }

          Where both runnables post.

          • account: string

            Gateway Slack account whose bot token posts (default default).

          • channel: string

            Conversation id the runnables post to.

          • OptionalpinnedTs?: string

            ts of the pinned quick-links message; unset: the harvester leaves it alone.

        • OptionalspecPath?: string

          Absolute path of the punch-list spec, linked from the pinned message and the harvest task.

        • timeZone: string

          The day rolls over in this IANA zone (day boundaries only, not when the runner fires).

      • siloRouting: {
            defaultBasePath?: string;
            silos: Record<
                string,
                {
                    basePath: string;
                    emailDomains?: string[];
                    githubOrgs?: (string | { githubOrg: string; relativePath: string })[];
                    jira?: boolean;
                    linear?: boolean;
                    slackWorkspaces?: string[];
                },
            >;
        }

        Data silos (Decision 28).

        • OptionaldefaultBasePath?: string

          Default silo base path. Default: paths().contentDir (Decision 28).

        • silos: Record<
              string,
              {
                  basePath: string;
                  emailDomains?: string[];
                  githubOrgs?: (string | { githubOrg: string; relativePath: string })[];
                  jira?: boolean;
                  linear?: boolean;
                  slackWorkspaces?: string[];
              },
          >

          Named silos.

      • OptionalskillReview?: {
            budgetAlertPercent: number;
            outputDir?: string;
            reportAccount: string;
            reportChannel: string;
            serverKey: string;
            timezone: string;
        }

        The daily Skill Workshop review (admin-review-skill-proposals); absent: it skips.

        • budgetAlertPercent: number

          Quiet-day alert threshold, percent of the catalog's character budget.

        • OptionaloutputDir?: string

          Report directory; default slack.channels.<reportChannel>.homeDir, required for a DM or a channel without one.

        • reportAccount: string

          Gateway Slack account whose bot posts (default default).

        • reportChannel: string

          Slack conversation the summary and the quiet-day alert go to.

        • serverKey: string

          jeeves-server machine key (in the server's own keys) that resolves the report's insider link.

        • timezone: string

          IANA zone of the report date (no default).

      • slack: {
            backfillBudgetSeconds: number;
            channelMeta?: {
                activityDays: number;
                descriptionMaxChars: number;
                excludeChannels: string[];
                maxChannels: number;
                outputDir?: string;
                pathRoots: Record<string, string>;
                relativeRoot?: string;
                reportAccount?: string;
                reportChannel?: string;
                reportTextAccounts?: string[];
                serverKey: string;
                sweepPatterns: string[];
                timezone: string;
                topicMaxChars: number;
                updateDescriptions: boolean;
                updateTopics: boolean;
            };
            channels: Record<string, { homeDir?: string; project?: string }>;
            newChannelLookbackDays?: number;
        }

        What this instance decides about Slack channels (Decision 9).

        • backfillBudgetSeconds: number

          slack-poll: the most time one channel may take in a run. A channel with a larger backlog saves its read position and resumes next run, so it can't starve the channels after it. Keep it well under the job's timeout.

        • OptionalchannelMeta?: {
              activityDays: number;
              descriptionMaxChars: number;
              excludeChannels: string[];
              maxChannels: number;
              outputDir?: string;
              pathRoots: Record<string, string>;
              relativeRoot?: string;
              reportAccount?: string;
              reportChannel?: string;
              reportTextAccounts?: string[];
              serverKey: string;
              sweepPatterns: string[];
              timezone: string;
              topicMaxChars: number;
              updateDescriptions: boolean;
              updateTopics: boolean;
          }

          slack-refresh-channel-meta (spec 2.6); absent: it skips.

          • activityDays: number

            Recent-message window for topics, in days.

          • descriptionMaxChars: number

            Longest description (Slack purpose) the runnable sets.

          • excludeChannels: string[]

            Channel ids left out.

          • maxChannels: number

            Channels sent to the worker per run; the rest wait.

          • OptionaloutputDir?: string

            Report directory; default slack.channels.<reportChannel>.homeDir, required when the report goes to a DM.

          • pathRoots: Record<string, string>

            A written path's first segment to the absolute directory it stands for.

          • OptionalrelativeRoot?: string

            Directory a back-ticked relative path is resolved against.

          • OptionalreportAccount?: string

            Gateway Slack account whose bot posts the summary; default found.

          • OptionalreportChannel?: string

            Summary target: a channel (C/G/D) or a user (U/W, their DM); default the OpenClaw command owner's DM.

          • OptionalreportTextAccounts?: string[]

            Gateway Slack accounts whose channels the report may name and quote; default the report target's own.

          • serverKey: string

            jeeves-server machine key (in the server's own keys) that resolves the report's insider link.

          • sweepPatterns: string[]

            Regular expressions (case-insensitive) a message must all match to assign a home directory.

          • timezone: string

            IANA zone of the report date (no default).

          • topicMaxChars: number

            Longest topic the runnable sets.

          • updateDescriptions: boolean

            false: report only, never set a description.

          • updateTopics: boolean

            false: report only, never set a topic.

        • channels: Record<string, { homeDir?: string; project?: string }>

          Per-channel decisions, keyed by channel id.

        • OptionalnewChannelLookbackDays?: number

          slack-poll: how far back to read a channel with no read position yet (newly joined or discovered). 0 starts from now; unset reads its full history.

      • Optionaltranscripts?: { libraryDir?: string; scratchDir?: string; userAgent?: string }

        Where transcripts-fetch-video files and caches transcripts.

        • OptionallibraryDir?: string

          Where transcripts are filed (default <default silo>/library/video-transcripts).

        • OptionalscratchDir?: string

          Raw API response cache (default {stateDir}/transcripts).

        • OptionaluserAgent?: string

          User-Agent sent to the transcript API (default jeeves-scripts/<instance.name>).

      When the file is missing, is not valid JSON, or fails schema validation (including a literal secret value anywhere in the tree).