agentplane 0.2.13 → 0.2.16

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.
package/README.md CHANGED
@@ -24,6 +24,9 @@ agentplane init
24
24
  agentplane quickstart
25
25
  ```
26
26
 
27
+ `agentplane init` is human-oriented: interactive onboarding includes workflow/backend selection,
28
+ execution profile selection (`conservative|balanced|aggressive`), approval toggles, and optional recipes.
29
+
27
30
  Create your first task and run the workflow:
28
31
 
29
32
  ```bash
@@ -45,6 +48,7 @@ npx agentplane quickstart
45
48
  - `AGENTS.md` is created if missing and defines the policy/guardrails.
46
49
  - Built-in agent definitions are copied into `.agentplane/agents/`.
47
50
  - Optional recipes can install additional agents when you run `agentplane recipes install ...`.
51
+ - `.agentplane/config.json` stores execution defaults under `execution` (profile, reasoning effort, tool budget, safety gates).
48
52
 
49
53
  ## Upgrade review reports
50
54
 
package/assets/AGENTS.md CHANGED
@@ -107,6 +107,23 @@ Outside-repo includes (non-exhaustive):
107
107
  - modifying keychains, ssh keys, credential stores
108
108
  - any tool that mutates outside-repo state
109
109
 
110
+ ## Execution Profile
111
+
112
+ `execution` settings in `.agentplane/config.json` define operational behavior defaults for agents:
113
+
114
+ - `profile`: `conservative` / `balanced` / `aggressive`
115
+ - `reasoning_effort`: `low` / `medium` / `high`
116
+ - `tool_budget`: `{ discovery, implementation, verification }`
117
+ - `stop_conditions`: conditions that force a stop/re-plan/escalation
118
+ - `handoff_conditions`: conditions that trigger handoff to another role
119
+ - `unsafe_actions_requiring_explicit_user_ok`: actions that require explicit user confirmation
120
+
121
+ Scope and precedence:
122
+
123
+ - These settings tune execution style only (autonomy, effort, budget, stop/handoff heuristics).
124
+ - They MUST NOT override role authority boundaries, source-of-truth order, approval gates, or hard invariants defined in this `AGENTS.md`.
125
+ - If `execution` config conflicts with policy, `AGENTS.md` policy wins.
126
+
110
127
  ## Framework Upgrade / Prompt Merge
111
128
 
112
129
  `agentplane upgrade` is responsible for mechanical upgrades and safe merges. When an upgrade run indicates a potential semantic conflict (for example, both local and incoming changes exist relative to a baseline, or a baseline is missing but files differ), treat the result as requiring a meaning-level review.
@@ -1 +1 @@
1
- {"version":3,"file":"redmine-backend.d.ts","sourceRoot":"","sources":["../../../src/backends/task-backend/redmine-backend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redmine-backend.d.ts","sourceRoot":"","sources":["../../../src/backends/task-backend/redmine-backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA0BvD,OAAO,EAkBL,KAAK,WAAW,EAChB,KAAK,QAAQ,EAEd,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,cAAe,YAAW,WAAW;IAChD,EAAE,SAAa;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,UAAU,uCAA8C;IACxD,aAAa,sBAA6B;gBAE9B,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;KAAE;IAsCtE,cAAc,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAoB3E,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAgBhC,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlD,cAAc,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAM/D,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAiBjD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC;IAKzD,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAM3C,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0C1E,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCvE,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA0DxC,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5C,IAAI,CAAC,IAAI,EAAE;QACf,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;QAC3B,QAAQ,EAAE,MAAM,GAAG,cAAc,GAAG,eAAe,GAAG,MAAM,CAAC;QAC7D,KAAK,EAAE,OAAO,CAAC;QACf,OAAO,EAAE,OAAO,CAAC;KAClB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjB,OAAO,CAAC,iBAAiB;YAOX,QAAQ;YAoBR,QAAQ;YAoCR,cAAc;IAsB5B,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,WAAW;YAML,SAAS;IAMvB,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,wBAAwB;YAQlB,eAAe;IAa7B,OAAO,CAAC,gBAAgB;YAIV,iBAAiB;IAgB/B,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,iBAAiB;YAIX,kBAAkB;IAchC,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,gBAAgB;YAIV,WAAW;CAgB1B"}
@@ -37,8 +37,15 @@ export class RedmineBackend {
37
37
  this.batchPause = typeof settings.batch_pause === "number" ? settings.batch_pause : 0.5;
38
38
  this.ownerAgent = firstNonEmptyString(envOwner, settings.owner_agent, "REDMINE");
39
39
  this.cache = opts.cache ?? null;
40
- if (!this.baseUrl || !this.apiKey || !this.projectId) {
41
- throw new BackendError(redmineConfigMissingMessage("url, api_key, project_id"), "E_BACKEND");
40
+ const missingEnvKeys = [];
41
+ if (!this.baseUrl)
42
+ missingEnvKeys.push("AGENTPLANE_REDMINE_URL");
43
+ if (!this.apiKey)
44
+ missingEnvKeys.push("AGENTPLANE_REDMINE_API_KEY");
45
+ if (!this.projectId)
46
+ missingEnvKeys.push("AGENTPLANE_REDMINE_PROJECT_ID");
47
+ if (missingEnvKeys.length > 0) {
48
+ throw new BackendError(redmineConfigMissingMessage(missingEnvKeys.join(", ")), "E_BACKEND");
42
49
  }
43
50
  if (!this.customFields?.task_id) {
44
51
  throw new BackendError(redmineConfigMissingMessage("custom_fields.task_id"), "E_BACKEND");
@@ -11,7 +11,7 @@ export class RedmineUnavailable extends BackendError {
11
11
  }
12
12
  }
13
13
  export function redmineConfigMissingMessage(detail) {
14
- return `Missing required Redmine config: ${detail}`;
14
+ return `Missing required Redmine configuration. Set ${detail} in environment variables (for example via .env).`;
15
15
  }
16
16
  export function redmineIssueIdMissingMessage() {
17
17
  return "Missing Redmine issue id for task";
@@ -0,0 +1,3 @@
1
+ export declare function renderInitWelcome(): string;
2
+ export declare function renderInitSection(title: string, description: string): string;
3
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/ui.ts"],"names":[],"mappings":"AAsBA,wBAAgB,iBAAiB,IAAI,MAAM,CAY1C;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAG5E"}
@@ -0,0 +1,37 @@
1
+ function useColor() {
2
+ return process.stdout.isTTY === true && (process.env.TERM ?? "dumb") !== "dumb";
3
+ }
4
+ function color(text, code) {
5
+ if (!useColor())
6
+ return text;
7
+ return `\u001B[${code}m${text}\u001B[0m`;
8
+ }
9
+ function padLine(line, width) {
10
+ if (line.length >= width)
11
+ return line;
12
+ return `${line}${" ".repeat(width - line.length)}`;
13
+ }
14
+ function box(lines) {
15
+ const width = Math.max(...lines.map((line) => line.length), 0);
16
+ const top = `┌${"─".repeat(width + 2)}┐`;
17
+ const body = lines.map((line) => `│ ${padLine(line, width)} │`);
18
+ const bottom = `└${"─".repeat(width + 2)}┘`;
19
+ return [top, ...body, bottom].join("\n");
20
+ }
21
+ export function renderInitWelcome() {
22
+ const logo = [
23
+ "░█▀█░█▀▀░█▀▀░█▀█░▀█▀░░░█░█▀█░█░░░█▀█░█▀█░█▀▀",
24
+ "░█▀█░█░█░█▀▀░█░█░░█░░▄▀░░█▀▀░█░░░█▀█░█░█░█▀▀",
25
+ "░▀░▀░▀▀▀░▀▀▀░▀░▀░░▀░░▀░░░▀░░░▀▀▀░▀░▀░▀░▀░▀▀▀",
26
+ ].map((line) => color(line, "36"));
27
+ const subtitle = color("agent/plane", "36");
28
+ const intro = [
29
+ color("Bootstrap an agent-first workflow in this repository.", "1"),
30
+ "This interactive setup runs once; daily work is executed by agents.",
31
+ ];
32
+ return `${logo.join("\n")}\n${subtitle}\n\n${box(intro)}\n\n`;
33
+ }
34
+ export function renderInitSection(title, description) {
35
+ const header = color(`[${title}]`, "33");
36
+ return `${header}\n${description}\n\n`;
37
+ }
@@ -1,4 +1,16 @@
1
- export declare function ensureAgentplaneDirs(agentplaneDir: string): Promise<void>;
1
+ export type InitExecutionConfig = {
2
+ profile: "conservative" | "balanced" | "aggressive";
3
+ reasoning_effort: "low" | "medium" | "high";
4
+ tool_budget: {
5
+ discovery: number;
6
+ implementation: number;
7
+ verification: number;
8
+ };
9
+ stop_conditions: string[];
10
+ handoff_conditions: string[];
11
+ unsafe_actions_requiring_explicit_user_ok: string[];
12
+ };
13
+ export declare function ensureAgentplaneDirs(agentplaneDir: string, backend: "local" | "redmine"): Promise<void>;
2
14
  export declare function writeInitConfig(opts: {
3
15
  agentplaneDir: string;
4
16
  gitRoot: string;
@@ -7,9 +19,10 @@ export declare function writeInitConfig(opts: {
7
19
  requirePlanApproval: boolean;
8
20
  requireNetworkApproval: boolean;
9
21
  requireVerifyApproval: boolean;
22
+ execution: InitExecutionConfig;
10
23
  }): Promise<void>;
11
24
  export declare function writeBackendStubs(opts: {
12
- localBackendPath: string;
13
- redmineBackendPath: string;
25
+ backend: "local" | "redmine";
26
+ backendPath: string;
14
27
  }): Promise<void>;
15
28
  //# sourceMappingURL=write-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write-config.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-config.ts"],"names":[],"mappings":"AAOA,wBAAsB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO/E;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAAC;IACjC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,sBAAsB,EAAE,OAAO,CAAC;IAChC,qBAAqB,EAAE,OAAO,CAAC;CAChC,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBhB"}
1
+ {"version":3,"file":"write-config.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-config.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC;IACpD,gBAAgB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC5C,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,yCAAyC,EAAE,MAAM,EAAE,CAAC;CACrD,CAAC;AAEF,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,OAAO,GAAG,SAAS,GAC3B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAAC;IACjC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,sBAAsB,EAAE,OAAO,CAAC;IAChC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,SAAS,EAAE,mBAAmB,CAAC;CAChC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhB"}
@@ -2,13 +2,13 @@ import { mkdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { defaultConfig, saveConfig, setByDottedKey } from "@agentplaneorg/core";
4
4
  import { writeJsonStableIfChanged } from "../../../../shared/write-if-changed.js";
5
- export async function ensureAgentplaneDirs(agentplaneDir) {
5
+ export async function ensureAgentplaneDirs(agentplaneDir, backend) {
6
6
  await mkdir(agentplaneDir, { recursive: true });
7
7
  await mkdir(path.join(agentplaneDir, "tasks"), { recursive: true });
8
8
  await mkdir(path.join(agentplaneDir, "agents"), { recursive: true });
9
9
  await mkdir(path.join(agentplaneDir, "cache"), { recursive: true });
10
- await mkdir(path.join(agentplaneDir, "backends", "local"), { recursive: true });
11
- await mkdir(path.join(agentplaneDir, "backends", "redmine"), { recursive: true });
10
+ await mkdir(path.join(agentplaneDir, "backends"), { recursive: true });
11
+ await mkdir(path.join(agentplaneDir, "backends", backend), { recursive: true });
12
12
  }
13
13
  export async function writeInitConfig(opts) {
14
14
  const rawConfig = defaultConfig();
@@ -17,6 +17,7 @@ export async function writeInitConfig(opts) {
17
17
  setByDottedKey(rawConfig, "agents.approvals.require_plan", String(opts.requirePlanApproval));
18
18
  setByDottedKey(rawConfig, "agents.approvals.require_network", String(opts.requireNetworkApproval));
19
19
  setByDottedKey(rawConfig, "agents.approvals.require_verify", String(opts.requireVerifyApproval));
20
+ setByDottedKey(rawConfig, "execution", JSON.stringify(opts.execution));
20
21
  await saveConfig(opts.agentplaneDir, rawConfig);
21
22
  }
22
23
  export async function writeBackendStubs(opts) {
@@ -29,13 +30,10 @@ export async function writeBackendStubs(opts) {
29
30
  id: "redmine",
30
31
  version: 1,
31
32
  settings: {
32
- url: "https://redmine.example",
33
- api_key: "replace-me",
34
- project_id: "replace-me",
35
33
  owner_agent: "REDMINE",
36
34
  custom_fields: { task_id: 1 },
37
35
  },
38
36
  };
39
- await writeJsonStableIfChanged(opts.localBackendPath, localBackendPayload);
40
- await writeJsonStableIfChanged(opts.redmineBackendPath, redmineBackendPayload);
37
+ const payload = opts.backend === "redmine" ? redmineBackendPayload : localBackendPayload;
38
+ await writeJsonStableIfChanged(opts.backendPath, payload);
41
39
  }
@@ -0,0 +1,4 @@
1
+ export declare function ensureInitRedmineEnvTemplate(opts: {
2
+ gitRoot: string;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=write-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-env.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-env.ts"],"names":[],"mappings":"AAkEA,wBAAsB,4BAA4B,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC3F"}
@@ -0,0 +1,89 @@
1
+ import path from "node:path";
2
+ import { readFile } from "node:fs/promises";
3
+ import { writeTextIfChanged } from "../../../../shared/write-if-changed.js";
4
+ const REDMINE_ENV_TEMPLATE = [
5
+ {
6
+ key: "AGENTPLANE_REDMINE_URL",
7
+ value: "https://redmine.example",
8
+ comment: "Redmine base URL.",
9
+ required: true,
10
+ },
11
+ {
12
+ key: "AGENTPLANE_REDMINE_API_KEY",
13
+ value: "replace-me",
14
+ comment: "Redmine API key.",
15
+ required: true,
16
+ },
17
+ {
18
+ key: "AGENTPLANE_REDMINE_PROJECT_ID",
19
+ value: "replace-me",
20
+ comment: "Project identifier (numeric ID or project slug).",
21
+ required: true,
22
+ },
23
+ {
24
+ key: "AGENTPLANE_REDMINE_OWNER_AGENT",
25
+ value: "REDMINE",
26
+ comment: "Optional default owner agent.",
27
+ required: false,
28
+ },
29
+ {
30
+ key: "AGENTPLANE_REDMINE_ASSIGNEE_ID",
31
+ value: "",
32
+ comment: "Optional assignee numeric ID.",
33
+ required: false,
34
+ },
35
+ ];
36
+ async function readTextIfExists(filePath) {
37
+ try {
38
+ return await readFile(filePath, "utf8");
39
+ }
40
+ catch (err) {
41
+ const code = err?.code;
42
+ if (code === "ENOENT")
43
+ return null;
44
+ throw err;
45
+ }
46
+ }
47
+ function collectDefinedEnvKeys(dotEnvText) {
48
+ const keys = new Set();
49
+ for (const line of dotEnvText.split(/\r?\n/u)) {
50
+ const trimmed = line.trim();
51
+ if (!trimmed || trimmed.startsWith("#"))
52
+ continue;
53
+ const match = /^([A-Za-z_][A-Za-z0-9_]*)\s*=/u.exec(trimmed);
54
+ if (match?.[1])
55
+ keys.add(match[1]);
56
+ }
57
+ return keys;
58
+ }
59
+ export async function ensureInitRedmineEnvTemplate(opts) {
60
+ const dotEnvPath = path.join(opts.gitRoot, ".env");
61
+ const existing = (await readTextIfExists(dotEnvPath)) ?? "";
62
+ const definedKeys = collectDefinedEnvKeys(existing);
63
+ const missing = REDMINE_ENV_TEMPLATE.filter((entry) => !definedKeys.has(entry.key));
64
+ if (missing.length === 0)
65
+ return;
66
+ const required = missing.filter((item) => item.required);
67
+ const optional = missing.filter((item) => !item.required);
68
+ const requiredLines = required.flatMap((entry) => [
69
+ `# ${entry.comment}`,
70
+ `${entry.key}=${entry.value}`,
71
+ ]);
72
+ const optionalLines = optional.length === 0
73
+ ? []
74
+ : [
75
+ "",
76
+ "# Optional values:",
77
+ ...optional.flatMap((entry) => [`# ${entry.comment}`, `${entry.key}=${entry.value}`]),
78
+ ];
79
+ const lines = [
80
+ "# agentplane: redmine backend configuration",
81
+ "# Required values:",
82
+ ...requiredLines,
83
+ ...optionalLines,
84
+ ];
85
+ const block = `${lines.join("\n")}\n`;
86
+ const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n\n" : existing.length > 0 ? "\n" : "";
87
+ const next = `${existing}${prefix}${block}`;
88
+ await writeTextIfChanged(dotEnvPath, next);
89
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"write-gitignore.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-gitignore.ts"],"names":[],"mappings":"AAgCA,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB"}
1
+ {"version":3,"file":"write-gitignore.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-gitignore.ts"],"names":[],"mappings":"AAiCA,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB"}
@@ -14,6 +14,7 @@ async function readTextIfExists(filePath) {
14
14
  }
15
15
  const RUNTIME_IGNORE_LINES = [
16
16
  "# agentplane: ignore runtime/transient workspace artifacts",
17
+ ".env",
17
18
  ".agentplane/worktrees",
18
19
  ".agentplane/cache",
19
20
  ".agentplane/recipes-cache",
@@ -1,4 +1,5 @@
1
1
  import type { CommandHandler, CommandSpec } from "../../spec/spec.js";
2
+ type ExecutionProfile = "conservative" | "balanced" | "aggressive";
2
3
  type InitFlags = {
3
4
  ide?: "codex" | "cursor" | "windsurf";
4
5
  workflow?: "direct" | "branch_pr";
@@ -8,6 +9,8 @@ type InitFlags = {
8
9
  requirePlanApproval?: boolean;
9
10
  requireNetworkApproval?: boolean;
10
11
  requireVerifyApproval?: boolean;
12
+ executionProfile?: ExecutionProfile;
13
+ strictUnsafeConfirm?: boolean;
11
14
  recipes?: string[];
12
15
  force?: boolean;
13
16
  backup?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/init.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAetE,KAAK,SAAS,GAAG;IACf,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;IACtC,QAAQ,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAsBF,KAAK,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5D,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,UAAU,CAsJ5C,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,cAAc,CAAC,UAAU,CACmB,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/init.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAsBtE,KAAK,gBAAgB,GAAG,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC;AAuEnE,KAAK,SAAS,GAAG;IACf,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;IACtC,QAAQ,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAsBF,KAAK,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5D,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,UAAU,CA2K5C,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,cAAc,CAAC,UAAU,CACmB,CAAC"}
@@ -13,9 +13,76 @@ import { collectInitConflicts, handleInitConflicts } from "./init/conflicts.js";
13
13
  import { ensureGitRoot } from "./init/git.js";
14
14
  import { maybeSyncIde } from "./init/ide-sync.js";
15
15
  import { maybeInstallBundledRecipes } from "./init/recipes.js";
16
- import { ensureAgentplaneDirs, writeBackendStubs, writeInitConfig } from "./init/write-config.js";
16
+ import { ensureAgentplaneDirs, writeBackendStubs, writeInitConfig, } from "./init/write-config.js";
17
17
  import { ensureAgentsFiles } from "./init/write-agents.js";
18
18
  import { ensureInitGitignore } from "./init/write-gitignore.js";
19
+ import { ensureInitRedmineEnvTemplate } from "./init/write-env.js";
20
+ import { renderInitSection, renderInitWelcome } from "./init/ui.js";
21
+ function buildInitExecutionProfile(profile, opts) {
22
+ const shared = {
23
+ stop_conditions: [
24
+ "Missing required input blocks correctness.",
25
+ "Requested action expands scope or risk beyond approved plan.",
26
+ "Verification fails and remediation changes scope.",
27
+ ],
28
+ handoff_conditions: [
29
+ "Role boundary reached (for example CODER -> TESTER/REVIEWER).",
30
+ "Task depends_on prerequisites are incomplete.",
31
+ "Specialized agent is required.",
32
+ ],
33
+ };
34
+ const byProfile = {
35
+ conservative: {
36
+ profile: "conservative",
37
+ reasoning_effort: "high",
38
+ tool_budget: { discovery: 4, implementation: 8, verification: 8 },
39
+ ...shared,
40
+ unsafe_actions_requiring_explicit_user_ok: [
41
+ "Destructive git history operations.",
42
+ "Outside-repo read/write.",
43
+ "Credential, keychain, or SSH material changes.",
44
+ "Network actions when approvals are enabled.",
45
+ ],
46
+ },
47
+ balanced: {
48
+ profile: "balanced",
49
+ reasoning_effort: "medium",
50
+ tool_budget: { discovery: 6, implementation: 10, verification: 6 },
51
+ ...shared,
52
+ unsafe_actions_requiring_explicit_user_ok: [
53
+ "Destructive git history operations.",
54
+ "Outside-repo read/write.",
55
+ "Credential, keychain, or SSH material changes.",
56
+ ],
57
+ },
58
+ aggressive: {
59
+ profile: "aggressive",
60
+ reasoning_effort: "low",
61
+ tool_budget: { discovery: 10, implementation: 16, verification: 8 },
62
+ stop_conditions: [
63
+ "Requested action expands scope or risk beyond approved plan.",
64
+ "Verification fails and remediation changes scope.",
65
+ ],
66
+ handoff_conditions: [
67
+ "Role boundary reached (for example CODER -> TESTER/REVIEWER).",
68
+ "Specialized agent is required.",
69
+ ],
70
+ unsafe_actions_requiring_explicit_user_ok: [
71
+ "Destructive git history operations.",
72
+ "Outside-repo read/write.",
73
+ "Credential, keychain, or SSH material changes.",
74
+ ],
75
+ },
76
+ };
77
+ const resolved = structuredClone(byProfile[profile]);
78
+ if (opts?.strictUnsafeConfirm === true) {
79
+ const extra = "Network actions when approvals are disabled.";
80
+ if (!resolved.unsafe_actions_requiring_explicit_user_ok.includes(extra)) {
81
+ resolved.unsafe_actions_requiring_explicit_user_ok.push(extra);
82
+ }
83
+ }
84
+ return resolved;
85
+ }
19
86
  function parseBooleanValueForInit(flag, value) {
20
87
  const normalized = value.trim().toLowerCase();
21
88
  if (["1", "true", "yes", "y", "on"].includes(normalized))
@@ -90,6 +157,19 @@ export const initSpec = {
90
157
  valueHint: "<true|false>",
91
158
  description: "Require explicit approval before recording verification.",
92
159
  },
160
+ {
161
+ kind: "string",
162
+ name: "execution-profile",
163
+ valueHint: "<conservative|balanced|aggressive>",
164
+ choices: ["conservative", "balanced", "aggressive"],
165
+ description: "Execution profile preset controlling autonomy, reasoning, and tool budgets.",
166
+ },
167
+ {
168
+ kind: "string",
169
+ name: "strict-unsafe-confirm",
170
+ valueHint: "<true|false>",
171
+ description: "Require strict explicit confirmations for additional unsafe actions.",
172
+ },
93
173
  {
94
174
  kind: "string",
95
175
  name: "recipes",
@@ -165,6 +245,10 @@ export const initSpec = {
165
245
  requireVerifyApproval: requireVerifyRaw === undefined
166
246
  ? undefined
167
247
  : parseBooleanValueForInit("--require-verify-approval", requireVerifyRaw),
248
+ executionProfile: raw.opts["execution-profile"],
249
+ strictUnsafeConfirm: raw.opts["strict-unsafe-confirm"] === undefined
250
+ ? undefined
251
+ : parseBooleanValueForInit("--strict-unsafe-confirm", String(raw.opts["strict-unsafe-confirm"])),
168
252
  recipes: recipesRaw === undefined ? undefined : parseRecipesSelectionForInit(recipesRaw),
169
253
  force: raw.opts.force === true,
170
254
  backup: raw.opts.backup === true,
@@ -194,6 +278,8 @@ async function cmdInit(opts) {
194
278
  requirePlanApproval: true,
195
279
  requireNetworkApproval: true,
196
280
  requireVerifyApproval: true,
281
+ executionProfile: "balanced",
282
+ strictUnsafeConfirm: false,
197
283
  };
198
284
  let ide = flags.ide ?? defaults.ide;
199
285
  let workflow = flags.workflow ?? defaults.workflow;
@@ -203,6 +289,8 @@ async function cmdInit(opts) {
203
289
  let requirePlanApproval = flags.requirePlanApproval ?? defaults.requirePlanApproval;
204
290
  let requireNetworkApproval = flags.requireNetworkApproval ?? defaults.requireNetworkApproval;
205
291
  let requireVerifyApproval = flags.requireVerifyApproval ?? defaults.requireVerifyApproval;
292
+ let executionProfile = flags.executionProfile ?? defaults.executionProfile;
293
+ let strictUnsafeConfirm = flags.strictUnsafeConfirm ?? defaults.strictUnsafeConfirm;
206
294
  const isInteractive = process.stdin.isTTY && !flags.yes;
207
295
  if (!process.stdin.isTTY &&
208
296
  !flags.yes &&
@@ -218,30 +306,56 @@ async function cmdInit(opts) {
218
306
  });
219
307
  }
220
308
  if (isInteractive) {
309
+ const askChoice = async (label, choices, defaultValue) => {
310
+ const result = await promptChoice(`\n${label}`, choices, defaultValue);
311
+ process.stdout.write("\n");
312
+ return result;
313
+ };
314
+ const askYesNo = async (label, defaultValue) => {
315
+ const result = await promptYesNo(`\n${label}`, defaultValue);
316
+ process.stdout.write("\n");
317
+ return result;
318
+ };
319
+ const askInput = async (label) => {
320
+ const result = await promptInput(`\n${label}`);
321
+ process.stdout.write("\n");
322
+ return result;
323
+ };
324
+ process.stdout.write(renderInitWelcome());
325
+ process.stdout.write(renderInitSection("Workflow", "Choose how branches/backends/approvals should be initialized for this repository."));
221
326
  ide = flags.ide ?? defaults.ide;
222
327
  if (!flags.workflow) {
223
- const choice = await promptChoice("Select workflow mode", ["direct", "branch_pr"], workflow);
328
+ const choice = await askChoice("Workflow mode", ["direct", "branch_pr"], workflow);
224
329
  workflow = choice === "branch_pr" ? "branch_pr" : "direct";
225
330
  }
226
331
  if (!flags.backend) {
227
- const choice = await promptChoice("Select task backend", ["local", "redmine"], backend);
332
+ const choice = await askChoice("Task backend", ["local", "redmine"], backend);
228
333
  backend = choice === "redmine" ? "redmine" : "local";
229
334
  }
230
335
  if (flags.hooks === undefined) {
231
- hooks = await promptYesNo("Install git hooks?", hooks);
336
+ hooks = await askYesNo("Install managed git hooks now?", hooks);
337
+ }
338
+ process.stdout.write(renderInitSection("Execution Profile", "Set default autonomy/effort for agents. You can change this later in config."));
339
+ if (!flags.executionProfile) {
340
+ executionProfile = (await askChoice("Execution profile", ["conservative", "balanced", "aggressive"], executionProfile));
232
341
  }
342
+ if (flags.strictUnsafeConfirm === undefined) {
343
+ strictUnsafeConfirm = await askYesNo("Require strict explicit confirmation for extra unsafe actions?", strictUnsafeConfirm);
344
+ }
345
+ process.stdout.write(renderInitSection("Approvals", "Control whether plan/network/verification actions require explicit approval by default."));
233
346
  if (flags.requirePlanApproval === undefined) {
234
- requirePlanApproval = await promptYesNo("Require plan approval?", requirePlanApproval);
347
+ requirePlanApproval = await askYesNo("Require plan approval before work starts?", requirePlanApproval);
235
348
  }
236
349
  if (flags.requireNetworkApproval === undefined) {
237
- requireNetworkApproval = await promptYesNo("Require explicit approval for network access?", requireNetworkApproval);
350
+ requireNetworkApproval = await askYesNo("Require explicit approval for network actions?", requireNetworkApproval);
238
351
  }
239
352
  if (flags.requireVerifyApproval === undefined) {
240
- requireVerifyApproval = await promptYesNo("Require explicit approval for verification?", requireVerifyApproval);
353
+ requireVerifyApproval = await askYesNo("Require explicit approval before recording verification?", requireVerifyApproval);
241
354
  }
355
+ process.stdout.write(renderInitSection("Recipes", "Optional: install recipe packs now (comma-separated IDs) or choose none."));
242
356
  if (!flags.recipes) {
243
357
  process.stdout.write(`${renderBundledRecipesHint()}\n`);
244
- const answer = await promptInput("Install optional recipes (comma separated, or none): ");
358
+ const answer = await askInput("Install optional recipes (comma separated, or none): ");
245
359
  recipes = answer
246
360
  ? answer
247
361
  .split(",")
@@ -259,6 +373,8 @@ async function cmdInit(opts) {
259
373
  requirePlanApproval = flags.requirePlanApproval ?? defaults.requirePlanApproval;
260
374
  requireNetworkApproval = flags.requireNetworkApproval ?? defaults.requireNetworkApproval;
261
375
  requireVerifyApproval = flags.requireVerifyApproval ?? defaults.requireVerifyApproval;
376
+ executionProfile = flags.executionProfile ?? defaults.executionProfile;
377
+ strictUnsafeConfirm = flags.strictUnsafeConfirm ?? defaults.strictUnsafeConfirm;
262
378
  }
263
379
  validateBundledRecipesSelection(recipes);
264
380
  try {
@@ -283,10 +399,9 @@ async function cmdInit(opts) {
283
399
  path.join(resolved.agentplaneDir, "agents"),
284
400
  path.join(resolved.agentplaneDir, "cache"),
285
401
  path.join(resolved.agentplaneDir, "backends"),
286
- path.join(resolved.agentplaneDir, "backends", "local"),
287
- path.join(resolved.agentplaneDir, "backends", "redmine"),
402
+ path.join(resolved.agentplaneDir, "backends", backend),
288
403
  ];
289
- const initFiles = [configPath, localBackendPath, redmineBackendPath];
404
+ const initFiles = [configPath, backendPath];
290
405
  const conflicts = await collectInitConflicts({ initDirs, initFiles });
291
406
  await handleInitConflicts({
292
407
  gitRoot: resolved.gitRoot,
@@ -294,7 +409,8 @@ async function cmdInit(opts) {
294
409
  backup: flags.backup === true,
295
410
  force: flags.force === true,
296
411
  });
297
- await ensureAgentplaneDirs(resolved.agentplaneDir);
412
+ await ensureAgentplaneDirs(resolved.agentplaneDir, backend);
413
+ const execution = buildInitExecutionProfile(executionProfile, { strictUnsafeConfirm });
298
414
  await writeInitConfig({
299
415
  agentplaneDir: resolved.agentplaneDir,
300
416
  gitRoot: resolved.gitRoot,
@@ -303,8 +419,12 @@ async function cmdInit(opts) {
303
419
  requirePlanApproval,
304
420
  requireNetworkApproval,
305
421
  requireVerifyApproval,
422
+ execution,
306
423
  });
307
- await writeBackendStubs({ localBackendPath, redmineBackendPath });
424
+ await writeBackendStubs({ backend, backendPath });
425
+ if (backend === "redmine") {
426
+ await ensureInitRedmineEnvTemplate({ gitRoot: resolved.gitRoot });
427
+ }
308
428
  const { installPaths } = await ensureAgentsFiles({
309
429
  gitRoot: resolved.gitRoot,
310
430
  agentplaneDir: resolved.agentplaneDir,
@@ -316,6 +436,7 @@ async function cmdInit(opts) {
316
436
  gitRoot: resolved.gitRoot,
317
437
  includeAgentPromptFiles: flags.gitignoreAgents === true,
318
438
  });
439
+ installPaths.push(".gitignore");
319
440
  if (flags.gitignoreAgents) {
320
441
  await setPinnedBaseBranch({
321
442
  cwd: resolved.gitRoot,
@@ -1 +1 @@
1
- {"version":3,"file":"set-status.d.ts","sourceRoot":"","sources":["../../../src/commands/task/set-status.ts"],"names":[],"mappings":"AAOA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAcnC,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkJlB"}
1
+ {"version":3,"file":"set-status.d.ts","sourceRoot":"","sources":["../../../src/commands/task/set-status.ts"],"names":[],"mappings":"AAOA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAcnC,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiKlB"}
@@ -26,6 +26,16 @@ export async function cmdTaskSetStatus(opts) {
26
26
  const ctx = opts.ctx ??
27
27
  (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
28
28
  const config = ctx.config;
29
+ const executionProfile = String(config.execution?.profile ?? "balanced").toLowerCase();
30
+ if (opts.force &&
31
+ executionProfile === "conservative" &&
32
+ process.env.AGENTPLANE_EXECUTION_FORCE_OK !== "1") {
33
+ throw new CliError({
34
+ exitCode: 2,
35
+ code: "E_USAGE",
36
+ message: "Conservative execution profile blocks --force by default. Set AGENTPLANE_EXECUTION_FORCE_OK=1 to override.",
37
+ });
38
+ }
29
39
  const resolved = ctx.resolvedProject;
30
40
  const useStore = backendIsLocalFileBackend(ctx);
31
41
  const store = useStore ? getTaskStore(ctx) : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentplane",
3
- "version": "0.2.13",
3
+ "version": "0.2.16",
4
4
  "description": "Agent Plane CLI for task workflows, recipes, and project automation.",
5
5
  "keywords": [
6
6
  "agentplane",