@stratusagent/agents 0.11.6 → 0.11.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ import { type Skill } from '@stratusagent/core';
2
+ /**
3
+ * Where the built-in skill ships: `skills/stratus/SKILL.md` in this
4
+ * package, one level up from `src/` and `dist/` alike, so a source checkout
5
+ * and an installed package read the same file.
6
+ */
7
+ export declare const STRATUS_SKILL_PATH: string;
8
+ /**
9
+ * The `stratus` skill: how Stratus works, for every agent (`Skill.builtin`).
10
+ * Read from disk rather than inlined so it stays a plain `SKILL.md` that
11
+ * `stratus skill validate` and a reviewer can read, and so a reload sees an
12
+ * edit to a source checkout. The body is read when an agent asks for it;
13
+ * only the description travels with every turn.
14
+ */
15
+ export declare const loadStratusSkill: () => Promise<Skill>;
16
+ //# sourceMappingURL=builtin-skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-skills.d.ts","sourceRoot":"","sources":["../src/builtin-skills.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAIlE;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAwE,CAAC;AAExG;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,QAAa,OAAO,CAAC,KAAK,CAItD,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { STRATUS_SKILL_ID } from '@stratusagent/core';
4
+ import { createLazySkill, parseSkillDocument } from "./skills.js";
5
+ /**
6
+ * Where the built-in skill ships: `skills/stratus/SKILL.md` in this
7
+ * package, one level up from `src/` and `dist/` alike, so a source checkout
8
+ * and an installed package read the same file.
9
+ */
10
+ export const STRATUS_SKILL_PATH = fileURLToPath(new URL('../skills/stratus/SKILL.md', import.meta.url));
11
+ /**
12
+ * The `stratus` skill: how Stratus works, for every agent (`Skill.builtin`).
13
+ * Read from disk rather than inlined so it stays a plain `SKILL.md` that
14
+ * `stratus skill validate` and a reviewer can read, and so a reload sees an
15
+ * edit to a source checkout. The body is read when an agent asks for it;
16
+ * only the description travels with every turn.
17
+ */
18
+ export const loadStratusSkill = async () => {
19
+ const read = () => readFile(STRATUS_SKILL_PATH, 'utf8');
20
+ const document = parseSkillDocument(await read());
21
+ return { ...createLazySkill({ id: STRATUS_SKILL_ID, document, read }), builtin: true };
22
+ };
23
+ //# sourceMappingURL=builtin-skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-skills.js","sourceRoot":"","sources":["../src/builtin-skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,gBAAgB,EAAc,MAAM,oBAAoB,CAAC;AAElE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAElE;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,4BAA4B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAExG;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,IAAoB,EAAE;IACzD,MAAM,IAAI,GAAG,GAAoB,EAAE,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;IACzE,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAClD,OAAO,EAAE,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACzF,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -8,5 +8,7 @@ export { MEMORY_TOOL_NAME, createRememberTool, RECALL_TOOL_NAME, createRecallToo
8
8
  export { DELEGATE_TOOL_NAME, DELEGATED_BY_METADATA_KEY, ROOT_SESSION_ID_METADATA_KEY, DELEGATION_DEPTH_METADATA_KEY, DELEGATED_SESSION_ID_MARKER, isDelegatedSession, delegatingSessionIdOf, outstandingDelegationFor, withoutDelegation, type DelegateDispatch, type DelegateToolOptions, createDelegateTool, } from './tools/delegate.ts';
9
9
  export { SCHEDULE_EVERY_TOOL_NAME, SCHEDULE_AT_TOOL_NAME, SCHEDULE_LIST_TOOL_NAME, SCHEDULE_CANCEL_TOOL_NAME, createScheduleTools, } from './tools/schedule.ts';
10
10
  export { MESSAGE_SEND_TOOL_NAME, type OutboundMessenger, createMessageSendTool, } from './tools/message.ts';
11
+ export { CREDENTIAL_REQUEST_TOOL_NAME, type CredentialRequester, createCredentialRequestTool, } from './tools/credentials.ts';
11
12
  export { GATEWAY_ONLY_TOOL_NAMES } from './tools/gateway-only.ts';
13
+ export { loadStratusSkill, STRATUS_SKILL_PATH } from './builtin-skills.ts';
12
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,KAAK,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,SAAS,EACT,UAAU,GACX,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,4BAA4B,EAC5B,8BAA8B,EAC9B,KAAK,mBAAmB,EACxB,kBAAkB,EAClB,KAAK,4BAA4B,EACjC,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,cAAc,EACnB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,KAAK,mBAAmB,EACxB,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,wBAAwB,EACxB,2BAA2B,EAC3B,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,iBAAiB,EACjB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,4BAA4B,EAC5B,6BAA6B,EAC7B,2BAA2B,EAC3B,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,KAAK,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,iBAAiB,EACjB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,SAAS,EACT,UAAU,GACX,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,4BAA4B,EAC5B,8BAA8B,EAC9B,KAAK,mBAAmB,EACxB,kBAAkB,EAClB,KAAK,4BAA4B,EACjC,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,cAAc,EACnB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,KAAK,mBAAmB,EACxB,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,wBAAwB,EACxB,2BAA2B,EAC3B,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,iBAAiB,EACjB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,4BAA4B,EAC5B,6BAA6B,EAC7B,2BAA2B,EAC3B,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,sBAAsB,EACtB,KAAK,iBAAiB,EACtB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,4BAA4B,EAC5B,KAAK,mBAAmB,EACxB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -13,5 +13,7 @@ export { MEMORY_TOOL_NAME, createRememberTool, RECALL_TOOL_NAME, createRecallToo
13
13
  export { DELEGATE_TOOL_NAME, DELEGATED_BY_METADATA_KEY, ROOT_SESSION_ID_METADATA_KEY, DELEGATION_DEPTH_METADATA_KEY, DELEGATED_SESSION_ID_MARKER, isDelegatedSession, delegatingSessionIdOf, outstandingDelegationFor, withoutDelegation, createDelegateTool, } from "./tools/delegate.js";
14
14
  export { SCHEDULE_EVERY_TOOL_NAME, SCHEDULE_AT_TOOL_NAME, SCHEDULE_LIST_TOOL_NAME, SCHEDULE_CANCEL_TOOL_NAME, createScheduleTools, } from "./tools/schedule.js";
15
15
  export { MESSAGE_SEND_TOOL_NAME, createMessageSendTool, } from "./tools/message.js";
16
+ export { CREDENTIAL_REQUEST_TOOL_NAME, createCredentialRequestTool, } from "./tools/credentials.js";
16
17
  export { GATEWAY_ONLY_TOOL_NAMES } from "./tools/gateway-only.js";
18
+ export { loadStratusSkill, STRATUS_SKILL_PATH } from "./builtin-skills.js";
17
19
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,wEAAwE;AACxE,wEAAwE;AACxE,mEAAmE;AACnE,mDAAmD;AAEnD,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAyB,WAAW,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,iBAAiB,EAGjB,SAAS,EACT,UAAU,GACX,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,4BAA4B,EAC5B,8BAA8B,EAE9B,kBAAkB,EAGlB,qBAAqB,EAErB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAEL,oBAAoB,EAGpB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,wBAAwB,EACxB,2BAA2B,EAG3B,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAGL,iBAAiB,EACjB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,aAAa,GAEd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,4BAA4B,EAC5B,6BAA6B,EAC7B,2BAA2B,EAC3B,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EAGjB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,sBAAsB,EAEtB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,wEAAwE;AACxE,wEAAwE;AACxE,mEAAmE;AACnE,mDAAmD;AAEnD,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAyB,WAAW,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,iBAAiB,EAGjB,SAAS,EACT,UAAU,GACX,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,4BAA4B,EAC5B,8BAA8B,EAE9B,kBAAkB,EAGlB,qBAAqB,EAErB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAEL,oBAAoB,EAGpB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,wBAAwB,EACxB,2BAA2B,EAG3B,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAGL,iBAAiB,EACjB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,aAAa,GAEd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,4BAA4B,EAC5B,6BAA6B,EAC7B,2BAA2B,EAC3B,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EAGjB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,sBAAsB,EAEtB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,4BAA4B,EAE5B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/soul.d.ts CHANGED
@@ -17,6 +17,11 @@ export interface ParsedSoul {
17
17
  provider?: string;
18
18
  /** Model the soul prefers (e.g. "claude-opus-5"). Runtimes may override. */
19
19
  model?: string;
20
+ /**
21
+ * The language this agent writes in (`en-GB`), over the config file's
22
+ * `language` and the `en-US` default. See `resolveRuntimeConfig`.
23
+ */
24
+ language?: string;
20
25
  }
21
26
  export interface ParseSoulOptions {
22
27
  /** Seed for deterministic identity generation when the soul has no name. */
@@ -1 +1 @@
1
- {"version":3,"file":"soul.d.ts","sourceRoot":"","sources":["../src/soul.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUxF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,EAAE,UAAU,MAAM,KAAG,OAClB,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,MAAM,KAAG,MAWtD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,UAAS,gBAAqB,KAAG,UAkC1E,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,UAAU,KAAG,MA8B7C,CAAC"}
1
+ {"version":3,"file":"soul.d.ts","sourceRoot":"","sources":["../src/soul.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+C,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUvG;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,EAAE,UAAU,MAAM,KAAG,OAClB,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,MAAM,KAAG,MAWtD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,UAAS,gBAAqB,KAAG,UA2C1E,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,UAAU,KAAG,MAiC7C,CAAC"}
package/dist/soul.js CHANGED
@@ -1,4 +1,4 @@
1
- import { isListensMode, LISTENS_MODES } from '@stratusagent/core';
1
+ import { isLanguageTag, isListensMode, LISTENS_MODES } from '@stratusagent/core';
2
2
  import { defineAgent } from "./define.js";
3
3
  import { unquote, parseFrontmatterLines, extractFrontmatter, writeScalar, } from "./frontmatter.js";
4
4
  /**
@@ -7,7 +7,7 @@ import { unquote, parseFrontmatterLines, extractFrontmatter, writeScalar, } from
7
7
  * is nobody — see `AgentDefinition.delegates`.
8
8
  */
9
9
  export const isDelegateAllowed = (agent, targetId) => (agent.delegates ?? []).some((entry) => entry === '*' || entry === targetId);
10
- const SOUL_SCALAR_KEYS = ['name', 'id', 'provider', 'model', 'listens'];
10
+ const SOUL_SCALAR_KEYS = ['name', 'id', 'provider', 'model', 'listens', 'language'];
11
11
  const SOUL_LIST_KEYS = ['tools', 'skills', 'credentials', 'delegates'];
12
12
  /**
13
13
  * The soul edit that grants one delegate, as the refusal suggests it. The
@@ -49,6 +49,11 @@ export const parseSoul = (source, options = {}) => {
49
49
  if (scalars.listens !== undefined && !isListensMode(scalars.listens)) {
50
50
  throw new Error(`Soul frontmatter listens: ${JSON.stringify(scalars.listens)} is not a listening mode; use one of ${LISTENS_MODES.join(', ')}.`);
51
51
  }
52
+ // Strict for the same reason, and for one more: the tag is interpolated
53
+ // into every prompt the agent is sent, so it may only be a tag.
54
+ if (scalars.language !== undefined && !isLanguageTag(scalars.language)) {
55
+ throw new Error(`Soul frontmatter language: ${JSON.stringify(scalars.language)} is not a language tag; use one like en-US or en-GB.`);
56
+ }
52
57
  const agent = defineAgent({
53
58
  ...(scalars.name ? { name: scalars.name } : {}),
54
59
  ...(scalars.id ? { id: scalars.id } : {}),
@@ -64,6 +69,7 @@ export const parseSoul = (source, options = {}) => {
64
69
  agent,
65
70
  ...(scalars.provider ? { provider: scalars.provider } : {}),
66
71
  ...(scalars.model ? { model: scalars.model } : {}),
72
+ ...(isLanguageTag(scalars.language) ? { language: scalars.language } : {}),
67
73
  };
68
74
  };
69
75
  export const formatSoul = (soul) => {
@@ -77,6 +83,9 @@ export const formatSoul = (soul) => {
77
83
  if (soul.agent.listens) {
78
84
  lines.push(`listens: ${soul.agent.listens}`);
79
85
  }
86
+ if (soul.language) {
87
+ lines.push(`language: ${soul.language}`);
88
+ }
80
89
  for (const [key, values] of [
81
90
  ['tools', soul.agent.tools],
82
91
  ['skills', soul.agent.skills],
package/dist/soul.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"soul.js","sourceRoot":"","sources":["../src/soul.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"soul.js","sourceRoot":"","sources":["../src/soul.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import type { CredentialDelivery, CredentialScope, Session, Tool } from '@stratusagent/core';
2
+ export declare const CREDENTIAL_REQUEST_TOOL_NAME = "credential.request";
3
+ /**
4
+ * Asks a human for a credential. The gateway implements it: it checks the
5
+ * request, puts it to someone (a form in this conversation, or a one-time
6
+ * link for the agent to pass on), and answers with how. It throws, with a
7
+ * sentence the agent can repeat, when the request cannot be put to anyone.
8
+ *
9
+ * `via` absent means a form where the conversation can show one and a link
10
+ * where it cannot. `formUnavailable` says why a link came back when no link
11
+ * was asked for.
12
+ */
13
+ export type CredentialRequester = (request: {
14
+ name: string;
15
+ scope: CredentialScope;
16
+ reason?: string;
17
+ via?: CredentialDelivery;
18
+ }, session: Session) => Promise<{
19
+ requestId: string;
20
+ via: 'form';
21
+ } | {
22
+ requestId: string;
23
+ via: 'link';
24
+ url: string;
25
+ expiresAt: string;
26
+ localOnly?: boolean;
27
+ formUnavailable?: string;
28
+ }>;
29
+ /**
30
+ * Ask the operator for a named credential this agent does not hold.
31
+ *
32
+ * The value never comes back through here, or anywhere the model can see:
33
+ * the channel puts a form in front of an approver, the form's answer goes
34
+ * straight to the credential store, and the name is added to this agent's
35
+ * soul so its tools can use it from the next reply. An agent that went
36
+ * searching its files and environment for a key its operator had stored
37
+ * elsewhere is why the path exists, and why the only thing an agent can do
38
+ * with a secret is ask for one.
39
+ *
40
+ * `safe`: it asks a question in the conversation the agent is already in,
41
+ * and a human decides everything after that.
42
+ */
43
+ export declare const createCredentialRequestTool: (requestCredential: CredentialRequester) => Tool;
44
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/tools/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAc,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAEzG,eAAO,MAAM,4BAA4B,uBAAuB,CAAC;AAEjE;;;;;;;;;GASG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,eAAe,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,kBAAkB,CAAA;CAAE,EAC5F,OAAO,EAAE,OAAO,KACb,OAAO,CACR;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,CACpH,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,2BAA2B,GAAI,mBAAmB,mBAAmB,KAAG,IA6DnF,CAAC"}
@@ -0,0 +1,78 @@
1
+ export const CREDENTIAL_REQUEST_TOOL_NAME = 'credential.request';
2
+ /**
3
+ * Ask the operator for a named credential this agent does not hold.
4
+ *
5
+ * The value never comes back through here, or anywhere the model can see:
6
+ * the channel puts a form in front of an approver, the form's answer goes
7
+ * straight to the credential store, and the name is added to this agent's
8
+ * soul so its tools can use it from the next reply. An agent that went
9
+ * searching its files and environment for a key its operator had stored
10
+ * elsewhere is why the path exists, and why the only thing an agent can do
11
+ * with a secret is ask for one.
12
+ *
13
+ * `safe`: it asks a question in the conversation the agent is already in,
14
+ * and a human decides everything after that.
15
+ */
16
+ export const createCredentialRequestTool = (requestCredential) => ({
17
+ name: CREDENTIAL_REQUEST_TOOL_NAME,
18
+ description: 'Ask your operator for a named credential you do not hold (for example github.token). They are shown a form to add it, in this conversation where it can show one, or behind a one-time link you are given to pass on; you never see the value, and once they add it the tools that need it can use it from your next reply. Scope "agent" (the default) keeps it yours alone; "shared" stores it once for the fleet, but it is granted only to you: another agent can use it only once its own soul lists the name.',
19
+ risk: 'safe',
20
+ parameters: {
21
+ type: 'object',
22
+ properties: {
23
+ name: { type: 'string', description: 'The credential name, as the tool that needs it documents it: search.apiKey, github.token.' },
24
+ scope: { type: 'string', enum: ['agent', 'shared'], description: 'Where the key is stored. Default "agent", for you alone; "shared" stores one value other agents can be granted too.' },
25
+ reason: { type: 'string', description: 'One sentence on what you need it for, shown to the person asked.' },
26
+ via: {
27
+ type: 'string',
28
+ enum: ['form', 'link'],
29
+ description: 'How to ask. Omit it for a form here when this conversation can show one, and a link otherwise; "link" when the person would rather not enter the key in this conversation\'s app.',
30
+ },
31
+ },
32
+ required: ['name'],
33
+ },
34
+ async execute(input, session) {
35
+ const name = typeof input.name === 'string' ? input.name.trim() : '';
36
+ if (!name) {
37
+ throw new Error('credential.request needs "name", the credential to ask for.');
38
+ }
39
+ const scope = input.scope ?? 'agent';
40
+ if (scope !== 'agent' && scope !== 'shared') {
41
+ throw new Error('credential.request "scope" is "agent" (yours alone, the default) or "shared" (stored once for the fleet).');
42
+ }
43
+ const via = input.via;
44
+ if (via !== undefined && via !== 'form' && via !== 'link') {
45
+ throw new Error('credential.request "via" is "form" (in this conversation) or "link" (a one-time link to pass on); omit it to let the daemon choose.');
46
+ }
47
+ const reason = typeof input.reason === 'string' && input.reason.trim().length > 0 ? input.reason.trim() : undefined;
48
+ const asked = await requestCredential({
49
+ name,
50
+ scope,
51
+ ...(reason !== undefined ? { reason } : {}),
52
+ ...(via !== undefined ? { via } : {}),
53
+ }, session);
54
+ const after = 'You will not see the value; once they add it, the tools that need it can use it from your next reply.';
55
+ if (asked.via === 'form') {
56
+ return { requested: true, requestId: asked.requestId, name, scope, via: 'form', note: `Your operator was asked in this conversation. ${after}` };
57
+ }
58
+ return {
59
+ requested: true,
60
+ requestId: asked.requestId,
61
+ name,
62
+ scope,
63
+ via: 'link',
64
+ link: asked.url,
65
+ expiresAt: asked.expiresAt,
66
+ // Said to the agent because the agent is the one holding the link:
67
+ // whoever it hands it to can add the key, once.
68
+ note: `${asked.formUnavailable !== undefined ? `${asked.formUnavailable} ` : ''}`
69
+ + `Give this link to the person who should add ${name}: it opens a form for it, works once, and expires at ${asked.expiresAt}. `
70
+ + `Anyone holding it can add the key, so share it only with them, and never ask for the key itself in chat. `
71
+ + (asked.localOnly === true
72
+ ? 'It points at the daemon\'s local address, so it opens only on the machine the daemon runs on; say so, and that setting api.publicUrl gives links that open elsewhere. '
73
+ : '')
74
+ + after,
75
+ };
76
+ },
77
+ });
78
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/tools/credentials.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-only.d.ts","sourceRoot":"","sources":["../../src/tools/gateway-only.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAOpD,CAAC"}
1
+ {"version":3,"file":"gateway-only.d.ts","sourceRoot":"","sources":["../../src/tools/gateway-only.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAQpD,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { CREDENTIAL_REQUEST_TOOL_NAME } from "./credentials.js";
1
2
  import { DELEGATE_TOOL_NAME } from "./delegate.js";
2
3
  import { MESSAGE_SEND_TOOL_NAME } from "./message.js";
3
4
  import { SCHEDULE_EVERY_TOOL_NAME, SCHEDULE_AT_TOOL_NAME, SCHEDULE_LIST_TOOL_NAME, SCHEDULE_CANCEL_TOOL_NAME, } from "./schedule.js";
@@ -25,5 +26,6 @@ export const GATEWAY_ONLY_TOOL_NAMES = [
25
26
  SCHEDULE_CANCEL_TOOL_NAME,
26
27
  MESSAGE_SEND_TOOL_NAME,
27
28
  DELEGATE_TOOL_NAME,
29
+ CREDENTIAL_REQUEST_TOOL_NAME,
28
30
  ];
29
31
  //# sourceMappingURL=gateway-only.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-only.js","sourceRoot":"","sources":["../../src/tools/gateway-only.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAsB;IACxD,wBAAwB;IACxB,qBAAqB;IACrB,uBAAuB;IACvB,yBAAyB;IACzB,sBAAsB;IACtB,kBAAkB;CACnB,CAAC"}
1
+ {"version":3,"file":"gateway-only.js","sourceRoot":"","sources":["../../src/tools/gateway-only.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAsB;IACxD,wBAAwB;IACxB,qBAAqB;IACrB,uBAAuB;IACvB,yBAAyB;IACzB,sBAAsB;IACtB,kBAAkB;IAClB,4BAA4B;CAC7B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratusagent/agents",
3
- "version": "0.11.6",
3
+ "version": "0.11.7",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -11,13 +11,14 @@
11
11
  }
12
12
  },
13
13
  "files": [
14
- "dist"
14
+ "dist",
15
+ "skills"
15
16
  ],
16
17
  "engines": {
17
18
  "node": ">=22.13 <23 || >=23.4"
18
19
  },
19
20
  "dependencies": {
20
- "@stratusagent/core": "0.11.6"
21
+ "@stratusagent/core": "0.11.7"
21
22
  },
22
23
  "devDependencies": {
23
24
  "@types/node": "^24.6.0",
@@ -0,0 +1,234 @@
1
+ ---
2
+ name: stratus
3
+ description: Use whenever someone asks how Stratus itself works or how to set something up in it, such as where a config, credential, soul, log, or workspace lives, how to give you an API key or a new tool, why you can or cannot do something, what you remember and how to make you forget it, why a reply stopped partway or came from another model, which version is running, which stratus command does what, or how Slack, approvals, plugins, or the daemon behave. Read it before you search files or guess.
4
+ ---
5
+
6
+ # How Stratus works
7
+
8
+ You run inside Stratus: a daemon (`stratusd`, started by `stratus serve`) that hosts a roster of agents, connects them to channels like Slack, and runs their tools. This is the map of that system, so you can answer questions about your own setup accurately and ask your operator for exactly the right thing.
9
+
10
+ Check your instructions first. They name your id, your soul file, your workspace, the model answering as you, the credentials you hold (by name), the tools you have, and the room you are talking in. Those facts are about *you*, now, and they beat anything general below.
11
+
12
+ Four rules for using what follows:
13
+
14
+ - **Say what you can check, and check it.** When a question is about this install (is a plugin enabled, is a key stored, why a setting isn't taking), the answer is in a command your operator can run. Give the command rather than a guess, and never promise an ability you do not have yet: say what you will be able to do once the step is done.
15
+ - **Never ask anyone to paste a secret into a conversation**, and never offer to store one you were given in chat. If someone pastes one anyway, do not repeat it and never `memory.remember` it. Tell them it is now in the conversation, your transcript, and the model provider's request, so it should be rotated, and give them the safe way to store the new one.
16
+ - **Mind the room.** Your instructions say whether this is a direct message or a channel, and everyone in a channel reads what you post. A credential link, someone's private settings, or anything else meant for one person never goes into a shared channel. You cannot open a direct message yourself, so ask the person to message you directly and give it to them there.
17
+ - **Your tools run on the machine the daemon runs on**, not necessarily the computer of the person you are talking to. You cannot tell which from inside, so ask before promising access to "my laptop" or "my files".
18
+
19
+ ## Where things live
20
+
21
+ Everything is under `~/.stratus/` on the daemon's machine:
22
+
23
+ | Path | What it is |
24
+ | --- | --- |
25
+ | `config.json` | The global config, and the trusted one (see "Config"). `0600`, because a plugin's config in it can hold secrets such as `tool-shell`'s `env`, and every save keeps it that way; `stratus doctor` flags one other users can read |
26
+ | `credentials.json` | Provider sign-ins, channel secrets (Slack's tokens and any channel plugin's, under `channels.<kind>.<agentId>`), and named credentials. `0600`, and kept that way by Stratus, which is why it is edited with `stratus credential set` and `stratus channel set` rather than by hand |
27
+ | `agents/<file>.md` | A soul: one agent's identity and allowlists. The file name is not the id; the id is the soul's `id:`, or derived from its `name:`. Use the id your instructions give |
28
+ | `agents/<id>/` | That agent's state: `sessions.db`, `memory.jsonl`, `whitelist.json` (its standing approvals), and `workspace/` |
29
+ | `agents/<id>/workspace/` | The agent's own working directory, where `shell.run` starts by default |
30
+ | `fleet.db` | Schedules, and the index of every session |
31
+ | `skills/<id>/SKILL.md` | Skills the operator installed |
32
+ | `logs/stratusd.jsonl` | The daemon's structured log, read with `stratus logs` |
33
+ | `gateway.json`, `gateway-token` | Where the control API is listening, and its bearer token. `0600` |
34
+ | `stratusd.lock` | The running daemon's claim on this home: one daemon per home |
35
+
36
+ Deleting a soul file takes the agent off the roster but keeps its `agents/<id>/` state, its standing approvals included (a new agent given the same id inherits them), and its schedules in `fleet.db`. Deleting `agents/<id>/` erases its history, memories, grants, and files.
37
+
38
+ ## Your soul
39
+
40
+ A soul is a markdown file: frontmatter for identity and allowlists, then the persona as prose.
41
+
42
+ - `name`; `id` (derived from the name when absent, so renaming a soul with no `id:` changes it too; a changed id starts the agent fresh, and its old history, memories, and grants stay under the old id); `provider` and `model`; `language` (for example `en-GB`); `listens` (see "Slack").
43
+ - `tools:` is the allowlist of what you may call: exact names (`fs.read`) or toolset globs (`fs.*`). Omitted means every registered tool and `tools: []` means none. When you lack a tool, ask for that one name to be added. Never suggest deleting the list to fix it, because that grants every tool, the shell included.
44
+ - `skills:` enables skills. Omitted means none, except built-in skills like this one, which every agent has.
45
+ - `credentials:` names the credentials you may use. Omitted means none.
46
+ - `delegates:` names the agents `agent.delegate` may hand work to (`*` for anyone). Omitted means nobody.
47
+
48
+ Under `stratus serve` the daemon reads your soul again before every turn, so an edit reaches your next reply with no restart. Its contents are already in your instructions; there is nothing to open. A *new* soul file, or a deleted one, needs the roster reloaded: the dashboard and the control API do it (`POST /api/v1/roster/reload`), and so does `stratus restart`.
49
+
50
+ ## Config
51
+
52
+ The config decides which provider and model run, which plugins load, and how approvals work. The file is the one `--config` or `STRATUS_CONFIG` names, else a `stratus.config.json` in the directory the daemon started in (for the service, wherever `stratus service install` ran), else `~/.stratus/config.json`.
53
+
54
+ Which provider and model a turn uses: for `stratus run` and `stratus chat`, command-line flags beat `STRATUS_*` environment variables, which beat the soul's `provider`/`model`, which beat the file. Under `stratus serve` a soul's `provider`/`model` beats all of those, because each agent in a roster runs on its own. A changed `provider` or `model` in the config reaches the next turn without a restart.
55
+
56
+ A project-local `stratus.config.json` ships inside repositories, so it is **untrusted**. It cannot set `plugins`, `approvals`, `principals`, `slack`, `api`, `maxTurns`, `apiKeyEnv`, `soul`, `systemPrompt`, `executor`, or `memoryStore`. Those are read only from `~/.stratus/config.json` or a file named by `--config` or `STRATUS_CONFIG`. A project-local file that sets one of them has it ignored, with a warning. For `principals`, `slack`, `maxTurns`, `executor`, and `memoryStore` the daemon uses `~/.stratus/config.json`'s instead; for `plugins`, `approvals`, and `api` it uses none. A project-local file that says nothing about one of those eight leaves the global one in force.
57
+
58
+ When a setting "isn't taking", these say why:
59
+
60
+ - `stratus doctor` shows what `stratus run` and `stratus chat` would use, and which file or variable decided each value.
61
+ - `stratus agents` shows what each agent on the roster runs on.
62
+ - `stratus plugins` shows what the config's approvals mode does with each tool. `stratus serve --approvals` overrides that mode. A daemon in `remote` logs an `approvals: remote` line at startup, so a `stratus logs` with no such line since the last start means `headless`.
63
+
64
+ ## Credentials and API keys
65
+
66
+ This is the question you will be asked most. A secret reaches Stratus in one of four ways, and which one depends on what uses it:
67
+
68
+ - **Provider sign-ins** (the model's own key or subscription): `stratus setup` → Providers, or the dashboard. There is no `stratus login`.
69
+ - **Channel tokens** (a Slack app's tokens): `stratus setup` → Channels, or the dashboard. No agent can read them, yours included.
70
+ - **Named credentials**, such as `search.apiKey`, are for tools whose plugin declares that name. A web search backend is the common one: its key is always `search.apiKey`, whatever the vendor. These are the only secrets you can ask for yourself.
71
+ - **A shell command's or an MCP server's token** is not a named credential: `shell.run` and MCP servers never read the credential store. Your operator puts it in the trusted config at the machine, and the daemon needs a restart:
72
+ - for the shell, in `@stratusagent/tool-shell`'s `env`, under `agents.<id>` to keep it to one agent (whose commands can then read it). An agent's `env` is added to the shared one rather than replacing it, its own names win, and a name set to `null` there is withheld from that agent;
73
+ - for an MCP server, in `servers.<name>.headers` (HTTP) or `servers.<name>.env` (stdio), which every agent granted `mcp.<name>.*` uses. Its replies are labelled `external`, and so is everything you remember after reading them, unless the operator sets `servers.<name>.outputTrust` to `agent` (or `unknown`) for a server they run; never `user`.
74
+
75
+ `passEnv` beside them forwards variables, values included, from the daemon's own environment, and only ones that are not secret belong on it.
76
+
77
+ For a named credential to reach you, three things must all be true. It is **stored**, your soul's `credentials:` **lists its name**, and a tool you have **declares it**. Storing grants nothing by itself. You never see the value, and there is no file or variable for you to look in. Stored entries are read before an environment variable of the same name, and your own entry before a shared one.
78
+
79
+ When you need a named credential you do not hold, first make sure a tool you have uses that name. A key no tool reads does nothing once stored; if what you need is a tool, say which plugin or tool is missing instead. Then:
80
+
81
+ 1. **Ask with `credential.request`**, if your `tools:` covers it (a daemon tool; the built-in `stratus` agent, which has no soul, cannot use it). Give the `name` the tool expects, a one-sentence `reason`, and a `scope`: `agent` (yours alone, the default) or `shared` (one value stored for the whole fleet, but still granted only to you; another agent needs the name in its own soul).
82
+ - **A form**, in Slack, goes up in this conversation when one of `approvals.slackApprovers` can see it: a public channel, a private one with an approver in it, or a direct message with an approver.
83
+ - **A link** comes back otherwise, or when you pass `via: "link"`. It needs the control API, and without `api.publicUrl` it opens only on the daemon's machine. Anyone who has the link can set the key, once, within 30 minutes, with no approver involved, and opening it spends nothing. So give it only to your operator. In a shared channel, or a direct message with anyone else, do not post it: ask your operator to message you directly, and ask again there. Pass `via: "form"` to get a form or nothing.
84
+ - Either way the key goes straight to the store and the name into your soul, and you can use it from your next reply. A restart cancels a request still waiting.
85
+ 2. **Otherwise, ask your operator to run, on the machine:**
86
+
87
+ ```
88
+ read -rs KEY && printf %s "$KEY" | stratus credential set <name> --agent <your id>
89
+ ```
90
+
91
+ (leave out `--agent` for a shared one), and to add `<name>` to `credentials:` in your soul.
92
+
93
+ Away from the machine, named credentials are **add-only**: the control API, the Slack form, and the link can add a name nobody has stored, and refuse one already stored or supplied by the daemon's environment. Replacing or removing one is `stratus credential set` or `stratus credential remove` at the machine, because a replaced shared key moves every agent using it onto another account. `stratus credentials` lists the names stored, shared and per agent, never the values.
94
+
95
+ A stored named credential or provider key takes effect on the next turn, with no restart. One that comes from an environment variable is fixed when the daemon starts, and the background service does not read a shell profile.
96
+
97
+ When a stored key "isn't found", check in this order:
98
+
99
+ 1. Is the name in your `credentials:`?
100
+ 2. Does a tool you have use it? The plugin's README names what it reads.
101
+ 3. Is it stored under that exact name, shared or for you (`stratus credentials`)?
102
+
103
+ ## Tools, plugins, and approvals
104
+
105
+ - **Built in everywhere:** `memory.*` (remember, recall, forget, pin) and `skill.read`, which every agent has because this skill counts. **Only under the daemon:** `schedule.*`, `message.send`, `agent.delegate`, and `credential.request`, so `stratus run` and `stratus chat` cannot call them.
106
+ - **Plugins** add the rest, each installed with `npm install -g <package>` and enabled under `plugins` in the trusted config:
107
+ - `@stratusagent/tool-fs` gives `fs.*`, inside configured roots only, so with no roots there is no filesystem. Roots go in `"@stratusagent/tool-fs": { "enabled": true, "roots": ["~/notes"] }`, or under `"agents": { "<id>": { "roots": [...] } }` for one agent.
108
+ - `@stratusagent/tool-shell` gives `shell.run`.
109
+ - `@stratusagent/tool-web` gives `web.fetch`. `web.search` is not first-party: it comes from a search backend plugin someone else publishes, and needs `search.apiKey`.
110
+ - `@stratusagent/tool-browser` gives `browser.*`.
111
+ - `@stratusagent/plugin-mcp` gives an MCP server's tools as `mcp.<server>.<tool>`.
112
+ - `stratus setup` → Plugins installs, enables, and asks for settings like roots in one step.
113
+ - Enabled is not granted: your soul's `tools:` must also cover a plugin's tools. `stratus plugins` walks the whole chain for each tool (installed, enabled, granted to which agents, and what approvals do with a call), so it answers "why can't you use X" in one command.
114
+ - **Risk.** Every tool is `safe`, `gated`, or `dangerous`. The daemon runs `safe` tools unattended, among them `memory.*`, `skill.read`, `credential.request`, `agent.delegate`, `schedule.list`, `schedule.cancel`, and `fs.read`, `fs.list`, and `fs.search`. Gated tools include:
115
+ - `web.fetch`, `fs.write`, `shell.run`, `browser.*`, and `mcp.*`;
116
+ - `schedule.every`, `schedule.at`, and `message.send`;
117
+ - every third-party tool, `web.search` included.
118
+ - What happens to a gated call depends on the approvals mode. Under `headless` (the default) it is refused. Under `remote` the people in `approvals.slackApprovers` are asked in Slack (or through the control API's `/approvals`) with **Allow once**, **Always allow**, and **Deny**. Under `remote` with nobody to ask, it is refused too.
119
+ - Either way, what was already approved still runs unattended. For `shell.run` that is a command scope plus a built-in safe list of read-only commands (`git status`, `git log`, `git diff`, `pwd`, and a few more; not `ls`). For `browser.act` it is an approved site, and for other gated tools a standing grant.
120
+ - The exception is `approvals.externalContent: "gate"`, set for every agent or per agent under `approvals.agents.<id>`. Once your conversation has read external content (`web.fetch`, `browser.*`, `web.search`, or an `mcp.*` tool), no grant applies for the rest of it: every gated call is asked or, headless, refused, and **Always allow** is not offered. `safe` tools, the built-in read-only commands, and a schedule's pre-authorized destination still run. Your next conversation starts with its grants again.
121
+ - **Always allow** writes one of those to `agents/<id>/whitelist.json`, except for a tool that names a destination, such as `message.send`, where it lasts for the conversation. A `dangerous` call is never offered it.
122
+ - `stratus grants <id>` lists the grants, and `stratus grants revoke <id> --tool|--scope|--origin` takes one back. There is no command to add one: a headless daemon asks nobody, so it never creates a grant, and a call nobody has approved yet needs `remote` mode first.
123
+
124
+ ## Memory
125
+
126
+ - **What you have.** Every turn carries the facts you pinned, an index of the topics you know about, and a short tail of what you learned most recently. Everything else is reachable with `memory.recall`. `memory.remember` writes a fact, `memory.forget` retires one by id, and `memory.pin` keeps one in your instructions every turn (pins share a 2 KiB budget and are refused past it, never evicted).
127
+ - **Where it lives.** By default `agents/<id>/memory.jsonl`, one agent's own. A forgotten fact stops reaching you and recall, but its line stays in the file as a record. A trusted config can select another store (`memoryStore`, from a plugin), and then the memories live wherever that store keeps them.
128
+ - **Making you forget something.** Recall it to find its id and `memory.forget` it, then say you did. Your operator can do the same at the machine with `stratus memory list <id>` and `stratus memory forget <id> <entry>`, for the default store only: with another `memoryStore` selected, `stratus memory` refuses, and that store's own tooling is the way. Never claim a fact is gone without having forgotten it.
129
+ - **Trust labels.** Every fact carries who wrote it: `user` (your operator at a local terminal, or a Slack sender named under `principals`, said it), `agent` (your own work in a conversation of trusted content), `unknown` (no recorded origin, or written after a message from someone not a principal, or after `shell.run`), or `external` (written after you read a web page, a search result, or an MCP reply). Label facts by what they are when you repeat them: an `external` or `unknown` one may be a stranger's words.
130
+ - A label only ever goes down within a conversation, and only your operator can raise one, with `stratus memory reassert` at the machine. No tool can.
131
+
132
+ ## Slack
133
+
134
+ - **One Slack app per agent**, each with its own tokens, connected over Socket Mode, so no public address is needed. Set up with `stratus setup` → Channels, which prints the app manifest and checks the tokens.
135
+ - **"Sending messages to this app has been turned off"** in a DM is a Slack setting, not Stratus. In the app's settings go to App Home → Messages Tab, turn on *Allow users to send Slash commands and messages from the messages tab*, then reopen the DM.
136
+ - **What reaches you.** In a DM, every message. In a channel, a message that mentions you, which starts a thread. In that thread, what happens to a reply that does not name you depends on your soul's `listens:`:
137
+ - `thread`, the default, hears every such reply.
138
+ - `mentions` answers only messages that name you, though it still hears the rest of the thread.
139
+ - `judge` hears them and decides whether to answer.
140
+ - With several agents in one thread, an untagged reply goes to whoever spoke last. You hear a thread from the mention onward, never what came before it.
141
+ - **Answering only when mentioned**, never to thread replies, has three causes, and they are worth checking in this order:
142
+ 1. `listens: mentions` in your soul.
143
+ 2. Another agent spoke last in that thread.
144
+ 3. The app is missing the history scopes (`channels:history`, `groups:history`, `mpim:history`) and their `message.*` events, which means adding them and reinstalling the app.
145
+
146
+ Not answering at all also happens when the daemon is down, the app was removed from the channel, or `admit: "principals"` turned the person away.
147
+ - **Another agent on Slack** needs its own soul on the roster first, then its own Slack app through `stratus setup` → Channels, and a restart to connect it.
148
+ - **Who counts as your operator** is `principals.slackUsers` in the trusted config. Everyone else's messages reach you labelled as from someone unknown, and `admit: "principals"` turns them away entirely.
149
+ - **Images** need the `files:read` scope. Text files are read up to a size limit, and anything else reaches you by name only, with the reason. The message says which.
150
+
151
+ ## The daemon
152
+
153
+ - **Running it.** `stratus serve` runs the daemon in the foreground. `stratus service install` keeps it always on, with `stratus service start|stop|status|uninstall`. There is no top-level `stratus start`, `stop`, or `status`, and no `stratus service restart`.
154
+ - On macOS it is a LaunchAgent, started at login, not at power-on. `--no-login` also gives up restarts after a crash.
155
+ - On Linux it is a systemd user unit, which needs `loginctl enable-linger` to run while nobody is logged in.
156
+ - It will not start while the trusted config (`~/.stratus/config.json`, or the file `--config` names) fails to parse or validate. The error goes to stderr, not `stratus logs`: on Linux the unit then shows as failed until the file is fixed and `stratus service start` is run; on macOS launchd keeps retrying until the file is fixed. A daemon already running keeps its last good config, and `stratus service start`, `stratus update`, and `stratus restart` refuse up front with the same error rather than restart into it.
157
+ - **`stratus restart`** drains in-flight turns and restarts, and needs the control API. Without the API, use `stratus service stop` then `stratus service start`.
158
+ - A restart is needed after a change to `plugins` (a plugin's `env` included), `approvals`, `api`, `principals`, `slack`, `maxTurns`, `executor`, or `memoryStore`, and after new channel secrets (Slack's tokens or a channel plugin's).
159
+ - It is not needed for soul edits, stored credentials and keys, the config's `provider`/`model`, or skills (`stratus skill reload`).
160
+ - `stratus update` stops and starts the service itself. Only a daemon someone started with `stratus serve` needs restarting by hand.
161
+ - **`stratus logs`** (`-f` to follow, `--agent`, `--session`) reads the structured log. It records that tools ran and sessions finished, never prompts or replies. One exception: a failed session keeps the provider's error text, so skim a log before sharing it.
162
+ - A daemon that fails *before* it starts serving writes nothing there. Its error is in `~/.stratus/logs/stratusd.err.log` on macOS, in `journalctl --user-unit=stratusd.service` on Linux, or on the terminal that ran `stratus serve`.
163
+ - **The control API** is a separate install, `@stratusagent/control-api`, serving `/api/v1` on `127.0.0.1:4123`. The web dashboard is another, `@stratusagent/dashboard`, opened with `stratus dashboard`, which starts a daemon if none is running.
164
+ - From another device, the recommended path is a tunnel such as Tailscale, with `api.publicUrl` set to that address so credential links open there.
165
+
166
+ ## When a reply stops or changes model
167
+
168
+ - **"Out of steps."** One message may take `maxTurns` rounds of tool calls (default 40, set in the trusted config, restart to change). Past that you are told you are out of steps, get one last call with no tools, and answer with what you did and what is left. Replying "continue" carries on with a fresh allowance. An agent that does long work should have it raised.
169
+ - **Stopped with no reply.** On a provider that streams (Anthropic, Codex, and plugin providers that say they stream), the daemon's watchdog aborts a turn when the model reports nothing for `--idle-timeout` seconds (default 120). On one that does not, such as an OpenAI-compatible endpoint, there is no watchdog, and a silent request ends only when the provider's own request fails or times out, so `--idle-timeout` neither explains nor fixes it. The session ends failed, with `no activity for 120000ms`, and `stratus logs --agent <id>` names the last thing it heard. A tool that is running, or a call waiting on an approval, never trips it.
170
+ - **Cut off at the output cap.** A reply longer than the model may write in one turn fails rather than being posted half-finished, and the error says so. With an Anthropic API key that cap is `maxTokens` in the config (default 16000); a Claude subscription run does not take that setting, so raising it changes nothing there. Offer a shorter answer, or, on an API key, ask for the cap to be raised. Never ask for a longer timeout.
171
+ - **Answering on another model.** When the configured model fails a request and a `fallbackModel` is set, that conversation switches to the fallback and stays on it, even across restarts, so it never silently swaps back. Not every failure switches: a conversation too long for the window is trimmed and retried on the same model, a cancelled turn just stops, and a Codex or Claude subscription turn that fails after its tools already ran surfaces the error instead, since a retry elsewhere would run them twice. Those leave the conversation on the configured model, with nothing to roll over. Your instructions say when you are on the fallback. `stratus logs` shows the error that caused the switch, and `stratus session rollover <session id>` starts the conversation over on the configured model.
172
+ - When asked why a reply stopped, look before you answer if you can: with `shell.run` you can run `stratus logs --agent <your id>` (it is gated, so it needs approval or a granted scope), and an `fs` root covering `~/.stratus/logs/` lets you read the file. Without either, give the likely cause from what your transcript shows (an out-of-steps answer, a message with no reply, a request for a very long answer) and the log command that confirms it, rather than a certain answer.
173
+
174
+ ## Commands
175
+
176
+ | Command | What it does |
177
+ | --- | --- |
178
+ | `stratus setup` | The menu: providers, models, an agent, plugins, channels (Slack, and any channel an enabled plugin contributes), approvals, always-on |
179
+ | `stratus chat` / `stratus run` | Talk to an agent in the terminal, as a conversation or one prompt |
180
+ | `stratus serve` | Run the daemon in the foreground |
181
+ | `stratus service install\|uninstall\|start\|stop\|status` | Keep the daemon running as a background service |
182
+ | `stratus restart` | Announced drain-and-restart of the running daemon |
183
+ | `stratus logs` | Read the daemon's log |
184
+ | `stratus doctor` | What a run would use, and why |
185
+ | `stratus update` | Update Stratus and its companion packages (`--check` to look first) |
186
+ | `stratus dashboard` | Open the web dashboard with a one-time sign-in link |
187
+ | `stratus agent new` / `stratus agents` | Create an agent / list the roster |
188
+ | `stratus template add <path\|owner/repo>` | Install a packaged agent: soul, skills, and plugin config |
189
+ | `stratus skill add` / `stratus skill validate` / `stratus skill reload` | Install skills, check a skill directory, and have the running daemon re-read them |
190
+ | `stratus skills` | List skills and which agents enable each |
191
+ | `stratus plugins` | Every tool, its plugin, who is granted it, and what approvals do |
192
+ | `stratus credential set` / `stratus credential remove` / `stratus credentials` | Store (value on stdin) or remove a named credential; list the names |
193
+ | `stratus channel set` / `stratus channel remove` / `stratus channel list` | Store (values prompted without echo, or one per stdin line) or remove a channel's secrets for one agent; list which agents have them. A channel's secrets are never yours to read, and a running daemon picks them up at its next start |
194
+ | `stratus grants <id>` / `stratus grants revoke <id>` | An agent's standing approvals, and taking one back |
195
+ | `stratus schedules` / `stratus schedules cancel <id>` | Scheduled turns, and cancelling one |
196
+ | `stratus memory list` / `stratus memory search` / `stratus memory audit` | An agent's live memories with their trust labels, searched as the agent does, and every entry ever written |
197
+ | `stratus memory forget` / `stratus memory pin` / `stratus memory unpin` | Retire entries, or keep them in the agent's instructions every turn |
198
+ | `stratus memory export` / `stratus memory import` | Move an agent's memories to and from JSONL |
199
+ | `stratus memory reassert` | Re-label memories' trust as the operator; no tool can |
200
+ | `stratus session rollover <id>` | Start a long conversation over under the same id, keeping the old transcript |
201
+ | `stratus version` / `stratus help` | The version, and the full reference for every flag |
202
+
203
+ ## What you can do, and what to ask for
204
+
205
+ You can use the tools your soul grants, remember and recall, delegate to the agents you may delegate to, schedule turns and send messages if you have those tools, read your enabled skills, and ask for a named credential.
206
+
207
+ Your operator can do more from anywhere they reach the dashboard or the control API:
208
+
209
+ - **From the dashboard:** edit souls (your `tools:`, `credentials:`, and `listens:` included), create agents, answer approvals, change the provider, model, and other settings, and store provider sign-ins and Slack tokens.
210
+ - **Through the control API as well:** restart the daemon, revoke a grant, cancel a schedule, add a named credential, and edit `approvals`, `principals`, and `api`.
211
+
212
+ Only at the machine can someone:
213
+
214
+ - enable or configure a plugin (its `env` and `headers` included), or choose an executor or memory store;
215
+ - install or update packages;
216
+ - replace or remove a named credential;
217
+ - raise a memory's trust (`stratus memory reassert`).
218
+
219
+ When you need one of those, ask for it precisely, once: the exact command, the file and the line to change, and what it will let you do. For example: "Run `stratus credential set search.apiKey --agent kai` with the key on stdin, and add `search.apiKey` under `credentials:` in my soul. Once a search plugin is enabled, `web.search` is in my `tools:`, and approvals let it run, I can search." Not a list of possibilities, and not a guess presented as a step.
220
+
221
+ ## Going further
222
+
223
+ **Which version.** You are not told which version of Stratus is installed. `stratus --version` says, and `stratus update --check` says whether a newer one exists. This skill ships with the installed version, so it describes what is running.
224
+
225
+ The full documentation is at <https://github.com/stratuslabs/agent/tree/main/docs>. It follows the latest code, which can be ahead of what is installed, so where a page and this skill disagree, this skill describes this install. Link a person to the page that answers their question rather than reciting it:
226
+
227
+ - [Tools](https://github.com/stratuslabs/agent/blob/main/docs/guides/tools.md)
228
+ - [Shell](https://github.com/stratuslabs/agent/blob/main/docs/guides/shell.md)
229
+ - [Slack](https://github.com/stratuslabs/agent/blob/main/docs/guides/slack.md)
230
+ - [Approvals](https://github.com/stratuslabs/agent/blob/main/docs/guides/approvals.md)
231
+ - [Always on](https://github.com/stratuslabs/agent/blob/main/docs/guides/always-on.md)
232
+ - [Memory](https://github.com/stratuslabs/agent/blob/main/docs/concepts/memory.md)
233
+ - [Remote access](https://github.com/stratuslabs/agent/blob/main/docs/guides/remote-access.md)
234
+ - [Troubleshooting](https://github.com/stratuslabs/agent/blob/main/docs/guides/troubleshooting.md)