@bastani/atomic 0.9.0-alpha.2 → 0.9.0-alpha.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.0-alpha.3] - 2026-06-21
6
+
7
+ ### Fixed
8
+
9
+ - Fixed the repository `publish-release` workflow's final Publish-run verifier to poll GitHub Actions run JSON until a terminal state instead of treating a still-`in_progress` publish run as a failed prerelease.
10
+
5
11
  ## [0.9.0-alpha.2] - 2026-06-21
6
12
 
7
13
  ### Breaking Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/cursor",
3
- "version": "0.9.0-alpha.2",
3
+ "version": "0.9.0-alpha.3",
4
4
  "private": true,
5
5
  "description": "Experimental first-party Atomic extension for Cursor OAuth, model discovery, and streaming provider registration.",
6
6
  "contributors": [
@@ -40,7 +40,7 @@
40
40
  }
41
41
  },
42
42
  "dependencies": {
43
- "@bastani/atomic-natives": "0.9.0-alpha.2",
43
+ "@bastani/atomic-natives": "0.9.0-alpha.3",
44
44
  "@bufbuild/protobuf": "^2.0.0"
45
45
  }
46
46
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.9.0-alpha.2",
3
+ "version": "0.9.0-alpha.3",
4
4
  "private": true,
5
5
  "description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.9.0-alpha.2",
3
+ "version": "0.9.0-alpha.3",
4
4
  "private": true,
5
5
  "description": "Atomic extension that adapts MCP (Model Context Protocol) servers into the coding agent. Fork of: https://github.com/nicobailon/pi-mcp-adapter",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/subagents",
3
- "version": "0.9.0-alpha.2",
3
+ "version": "0.9.0-alpha.3",
4
4
  "private": true,
5
5
  "description": "Atomic extension for delegating tasks to subagents with chains, parallel execution, and TUI clarification. Fork of: https://github.com/nicobailon/pi-subagents",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/web-access",
3
- "version": "0.9.0-alpha.2",
3
+ "version": "0.9.0-alpha.3",
4
4
  "private": true,
5
5
  "description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
6
6
  "contributors": [
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.0-alpha.3] - 2026-06-21
10
+
11
+ ### Added
12
+
13
+ - Added a shared `prompt-refinement` stage to the builtin `ralph` and `goal` workflows. Both now run one `prompt-refinement` stage at the start that invokes the `prompt-engineer` skill (`/skill:prompt-engineer`) to sharpen the raw user request into a clearer, more actionable objective using the Workflow Best Practices prompt anatomy documented in `packages/coding-agent/docs/workflows.md` (`## Workflow Best Practices`). The refined request replaces the original as the operative objective for all downstream stages (research, orchestration, worker/review loops); the original request is preserved for traceability. `ralph` exposes `original_prompt` and `refined_prompt` outputs, and `goal` exposes `original_objective` (omitted when refinement left it unchanged) and records the original objective in the ledger and final report. The stage uses the same model chain as ralph's prompt-engineering stage (`promptEngineerModelConfig`).
14
+ - Renamed the builtin `ralph` workflow's per-iteration `prompt-engineer-${iteration}` stage to `research-prompt-refinement-${iteration}` (`renderPromptEngineerPrompt` → `renderResearchPromptRefinementPrompt`). It now consumes the clarity-refined request as input and continues to transform it into a codebase/online research question for the research stage.
15
+
9
16
  ## [0.9.0-alpha.2] - 2026-06-21
10
17
 
11
18
  ### Breaking Changes
@@ -21,12 +21,14 @@ export function appendLifecycleEvent(
21
21
 
22
22
  export async function createGoalLedger(
23
23
  objective: string,
24
+ originalObjective?: string,
24
25
  ): Promise<{ ledger: GoalLedger; ledgerPath: string; artifactDir: string }> {
25
26
  const artifactDir = await mkdtemp(join(tmpdir(), "atomic-goal-runner-"));
26
27
  const now = new Date().toISOString();
27
28
  const ledger: GoalLedger = {
28
29
  goal_id: randomUUID(),
29
30
  objective,
31
+ ...(originalObjective === undefined || originalObjective === objective ? {} : { original_objective: originalObjective }),
30
32
  status: "active",
31
33
  turns: 0,
32
34
  created_at: now,
@@ -35,6 +35,11 @@ export function renderFinalReport(
35
35
  "## Objective",
36
36
  ledger.objective,
37
37
  "",
38
+ ...(ledger.original_objective === undefined ? [] : [
39
+ "## Original objective (before prompt refinement)",
40
+ ledger.original_objective,
41
+ "",
42
+ ]),
38
43
  "## Final status",
39
44
  ledger.status,
40
45
  "",
@@ -29,6 +29,8 @@ import {
29
29
  renderGoalContinuationPrompt,
30
30
  renderReviewerPrompt,
31
31
  } from "./goal-prompts.js";
32
+ import { promptEngineerModelConfig } from "./ralph-models.js";
33
+ import { runPromptRefinementStage } from "./prompt-refinement.js";
32
34
 
33
35
  function positiveInteger(value: number | undefined, fallback: number): number {
34
36
  if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
@@ -72,16 +74,17 @@ type GoalRunnerContext = {
72
74
 
73
75
  export async function runGoalWorkflow(ctx: GoalRunnerContext): Promise<GoalWorkflowOutputs> {
74
76
  const inputs = ctx.inputs;
75
- const objective = inputs.objective.trim();
76
- if (!objective) {
77
+ const rawObjective = inputs.objective.trim();
78
+ if (!rawObjective) {
77
79
  throw new Error("goal requires an objective input.");
78
80
  }
81
+ const objective = await runPromptRefinementStage(ctx, { request: rawObjective, workflowLabel: "Goal", modelConfig: promptEngineerModelConfig });
79
82
 
80
83
  const maxTurns = positiveInteger(inputs.max_turns, DEFAULT_MAX_TURNS);
81
84
  const reviewQuorum = DEFAULT_REVIEW_QUORUM;
82
85
  const blockerThreshold = Math.min(DEFAULT_BLOCKER_THRESHOLD, maxTurns);
83
86
  const comparisonBaseBranch = normalizeBranchInput(inputs.base_branch, "origin/main");
84
- const { ledger, ledgerPath, artifactDir } = await createGoalLedger(objective);
87
+ const { ledger, ledgerPath, artifactDir } = await createGoalLedger(objective, rawObjective);
85
88
 
86
89
  const workerModelConfig = {
87
90
  model: "openai-codex/gpt-5.5:medium",
@@ -325,6 +328,7 @@ export async function runGoalWorkflow(ctx: GoalRunnerContext): Promise<GoalWorkf
325
328
  approved: ledger.status === "complete",
326
329
  goal_id: ledger.goal_id,
327
330
  objective: ledger.objective,
331
+ ...(ledger.original_objective === undefined ? {} : { original_objective: ledger.original_objective }),
328
332
  ledger_path: ledgerPath,
329
333
  turns_completed: ledger.turns,
330
334
  iterations_completed: ledger.turns,
@@ -93,6 +93,7 @@ export type GoalLifecycleEvent = {
93
93
  export type GoalLedger = {
94
94
  readonly goal_id: string;
95
95
  readonly objective: string;
96
+ readonly original_objective?: string;
96
97
  status: GoalStatus;
97
98
  turns: number;
98
99
  readonly created_at: string;
@@ -122,6 +123,7 @@ export type GoalWorkflowOutputs = {
122
123
  readonly approved?: boolean;
123
124
  readonly goal_id?: string;
124
125
  readonly objective?: string;
126
+ readonly original_objective?: string;
125
127
  readonly ledger_path?: string;
126
128
  readonly turns_completed?: number;
127
129
  readonly iterations_completed?: number;
@@ -27,6 +27,7 @@ export type GoalWorkflowOutputs = WorkflowOutputValues & {
27
27
  readonly approved?: boolean;
28
28
  readonly goal_id?: string;
29
29
  readonly objective?: string;
30
+ readonly original_objective?: string;
30
31
  readonly ledger_path?: string;
31
32
  readonly turns_completed?: number;
32
33
  readonly iterations_completed?: number;
@@ -33,7 +33,8 @@ export default workflow({
33
33
  )),
34
34
  approved: Type.Optional(Type.Boolean({ description: "Whether the reducer reached complete." })),
35
35
  goal_id: Type.Optional(Type.String({ description: "Per-run goal identifier stored in the ledger." })),
36
- objective: Type.Optional(Type.String({ description: "Normalized goal objective used by the run." })),
36
+ objective: Type.Optional(Type.String({ description: "Normalized goal objective used by the run (refined by the prompt-refinement stage)." })),
37
+ original_objective: Type.Optional(Type.String({ description: "The raw user-provided objective exactly as given, before prompt refinement. Omitted when refinement left it unchanged." })),
37
38
  ledger_path: Type.Optional(Type.String({ description: "OS-temp path to goal-ledger.json with receipts, reviewer decisions, blockers, and lifecycle events." })),
38
39
  turns_completed: Type.Optional(Type.Number({ description: "Worker/review turns completed." })),
39
40
  iterations_completed: Type.Optional(Type.Number({ description: "Worker/review turns completed, retained for status summaries." })),
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Shared prompt-refinement stage used by the ralph and goal workflows.
3
+ *
4
+ * Before the main work loop begins, both workflows run this single
5
+ * `prompt-refinement` stage. It invokes the prompt-engineer skill
6
+ * (`/skill:prompt-engineer`) to sharpen the raw user request into a clearer,
7
+ * more actionable objective using the Workflow Best Practices prompt anatomy
8
+ * documented in `packages/coding-agent/docs/workflows.md`. The refined request
9
+ * replaces the original as the operative objective downstream; the original is
10
+ * preserved by each workflow for reporting.
11
+ */
12
+
13
+ import type { WorkflowModelValue, WorkflowTaskOptions, WorkflowTaskResult } from "../src/shared/types.js";
14
+
15
+ export type PromptSection = readonly [tag: string, content: string];
16
+
17
+ /**
18
+ * Clarity rubric mirrored from the "## Workflow Best Practices" section of
19
+ * `docs/workflows.md` (the user-facing docs under packages/coding-agent/docs).
20
+ * The refinement stage makes each element explicit where it can be reasonably
21
+ * inferred from the raw request.
22
+ */
23
+ export const PROMPT_REFINEMENT_CRITERIA = [
24
+ "Apply the workflow best practices documented in the `## Workflow Best Practices` section of `docs/workflows.md`. Treat that section as the authoritative prompt-anatomy rubric: use its Objective, Context, Scope, Non-goals, Done criteria, Validation command, Reporting requirements, and Stop conditions when refining the request.",
25
+ "Objective — state what should be true when the work is complete.",
26
+ "Context — note why it matters and where the relevant code or area likely lives.",
27
+ "Scope — state what is allowed to change (the smallest correct change).",
28
+ "Non-goals — state what to avoid (unrelated refactors, redesigns, or behavior changes outside this case).",
29
+ "Done criteria — list verifiable completion signals: new behavior works, existing behavior is unchanged, and the validation command passes.",
30
+ "Validation command — name the targeted check that proves the result.",
31
+ "Reporting requirements — changed files, validation results, and remaining risks must be reported.",
32
+ "Stop conditions — name the cases where the agent should stop and ask first (public API, security, data migration, etc.).",
33
+ ].join("\n");
34
+
35
+ /**
36
+ * Build the prompt sent to the prompt-refinement stage. The refined request is
37
+ * returned verbatim (no fences or preamble) so it can replace the original
38
+ * request as the operative objective for the rest of the workflow.
39
+ */
40
+ export function renderPromptRefinementPrompt(args: {
41
+ readonly request: string;
42
+ readonly workflowLabel: string;
43
+ readonly workflowCwdContext?: PromptSection;
44
+ }): string {
45
+ const sections: readonly string[] = [
46
+ `/skill:prompt-engineer Refine the following user request into a clearer, more actionable objective for the ${args.workflowLabel} workflow. Improve clarity and completeness using the rubric below without changing the user's intent, expanding scope, or inventing requirements that cannot be reasonably inferred from the request.`,
47
+ `<original_request>\n${args.request}\n</original_request>`,
48
+ `<clarity_rubric>\nApply the Workflow Best Practices prompt anatomy. Make each of the following explicit where it can be reasonably inferred from the original request:\n${PROMPT_REFINEMENT_CRITERIA}\n</clarity_rubric>`,
49
+ [
50
+ "<refinement_rules>",
51
+ "- Preserve the user's original intent and scope; do not add unrelated work.",
52
+ "- If the original request is already clear and complete, return it essentially unchanged with only clarity improvements.",
53
+ "- Where a criterion cannot be reasonably inferred, state it as a concise assumption or a 'to confirm' note rather than fabricating specifics.",
54
+ "- Do not implement anything, run commands, or edit files. This stage only produces the refined request text.",
55
+ "</refinement_rules>",
56
+ ].join("\n"),
57
+ `<output_format>\nReturn ONLY the refined request. No preamble, no explanation, and no Markdown fences. The returned text replaces the original request as the operative objective for the rest of the workflow, so it must be a single self-contained request.\n</output_format>`,
58
+ ];
59
+ const tail = args.workflowCwdContext === undefined
60
+ ? []
61
+ : [`<${args.workflowCwdContext[0]}>\n${args.workflowCwdContext[1].trim()}\n</${args.workflowCwdContext[0]}>`];
62
+ return [...sections, ...tail].join("\n\n");
63
+ }
64
+
65
+ /** Minimal context surface required to run a tracked refinement stage. */
66
+ type PromptRefinementContext = {
67
+ task(name: string, options: WorkflowTaskOptions): Promise<WorkflowTaskResult>;
68
+ };
69
+
70
+ /** Model-chain + tool gating forwarded to the refinement stage session. */
71
+ export type PromptRefinementModelConfig = {
72
+ readonly model?: WorkflowModelValue;
73
+ readonly fallbackModels?: readonly string[];
74
+ readonly noTools?: "all" | "builtin";
75
+ readonly excludedTools?: readonly string[];
76
+ readonly tools?: readonly string[];
77
+ };
78
+
79
+ /**
80
+ * Run the shared `prompt-refinement` stage once and return the refined request.
81
+ * Falls back to the original request when the stage produces no usable text.
82
+ */
83
+ export async function runPromptRefinementStage(
84
+ ctx: PromptRefinementContext,
85
+ options: {
86
+ readonly request: string;
87
+ readonly workflowLabel: string;
88
+ readonly workflowCwdContext?: PromptSection;
89
+ readonly modelConfig: PromptRefinementModelConfig;
90
+ },
91
+ ): Promise<string> {
92
+ const result = await ctx.task("prompt-refinement", {
93
+ prompt: renderPromptRefinementPrompt({
94
+ request: options.request,
95
+ workflowLabel: options.workflowLabel,
96
+ ...(options.workflowCwdContext === undefined ? {} : { workflowCwdContext: options.workflowCwdContext }),
97
+ }),
98
+ ...options.modelConfig,
99
+ });
100
+ const refined = (result.text ?? "").trim();
101
+ return refined.length > 0 ? refined : options.request;
102
+ }
@@ -258,18 +258,18 @@ export function forkContinuationOptions(
258
258
  : { context: "fork", forkFromSessionFile: sessionFile };
259
259
  }
260
260
 
261
- export function renderPromptEngineerPrompt(args: {
261
+ export function renderResearchPromptRefinementPrompt(args: {
262
262
  readonly iteration: number;
263
263
  readonly maxLoops: number;
264
- readonly prompt: string;
264
+ readonly request: string;
265
265
  readonly workflowCwdContext: PromptSection;
266
266
  readonly latestReviewReportPath: string | undefined;
267
267
  }): string {
268
- const basePrompt = `/skill:prompt-engineer Transform the following user prompt to a codebase and online research question which can be thoroughly explored: ${args.prompt}`;
268
+ const basePrompt = `/skill:prompt-engineer Transform the following refined user request into a codebase and online research question which can be thoroughly explored: ${args.request}`;
269
269
  return [
270
270
  basePrompt,
271
271
  taggedPrompt([
272
- ["iteration", `Prompt engineering iteration ${args.iteration}/${args.maxLoops}.`],
272
+ ["iteration", `Research prompt refinement iteration ${args.iteration}/${args.maxLoops}.`],
273
273
  args.workflowCwdContext,
274
274
  [
275
275
  "review_findings",
@@ -404,5 +404,7 @@ export type RalphWorkflowResult = {
404
404
  readonly iterations_completed: number;
405
405
  readonly review_report: string;
406
406
  readonly review_report_path?: string;
407
+ readonly original_prompt: string;
408
+ readonly refined_prompt: string;
407
409
  };
408
410
 
@@ -4,6 +4,7 @@ import { tmpdir } from "node:os";
4
4
  import { join, resolve } from "node:path";
5
5
  import type { WorkflowRunContext, WorkflowTaskResult } from "../src/shared/types.js";
6
6
  import { E2E_VERIFICATION_GUIDANCE, WORKER_PREFLIGHT_CONTRACT } from "./shared-prompts.js";
7
+ import { runPromptRefinementStage } from "./prompt-refinement.js";
7
8
  import { reviewDecisionApproved } from "./ralph-review-gate.js";
8
9
  import {
9
10
  REVIEWER_COUNT,
@@ -14,7 +15,7 @@ import {
14
15
  defaultResearchPath,
15
16
  forkContinuationOptions,
16
17
  renderForkedOrchestratorPrompt,
17
- renderPromptEngineerPrompt,
18
+ renderResearchPromptRefinementPrompt,
18
19
  renderQaE2eVideoGuidance,
19
20
  renderResearchPrompt,
20
21
  reviewDecisionFromResult,
@@ -39,13 +40,7 @@ export async function runRalphWorkflow(
39
40
  ctx: WorkflowRunContext<RalphInputs>,
40
41
  options: RalphWorkflowOptions,
41
42
  ): Promise<RalphWorkflowResult> {
42
- const {
43
- prompt,
44
- maxLoops,
45
- comparisonBaseBranch,
46
- workflowStartCwd,
47
- createPr,
48
- } = options;
43
+ const { prompt, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr } = options;
49
44
  let latestReviewReportPath: string | undefined;
50
45
  let finalPlan = "";
51
46
  let finalPlanPath = "";
@@ -53,39 +48,40 @@ export async function runRalphWorkflow(
53
48
  let finalResearchPath = "";
54
49
  let finalResult = "";
55
50
  let finalPrReport: string | undefined;
56
- const workflowResearchPath = resolve(workflowStartCwd, defaultResearchPath(prompt));
57
- const implementationNotesPath = await createImplementationNotesFile(prompt);
51
+ const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
52
+ const refinedPrompt = await runPromptRefinementStage(ctx, { request: prompt, workflowLabel: "Ralph", workflowCwdContext, modelConfig: promptEngineerModelConfig });
53
+ const workflowResearchPath = resolve(workflowStartCwd, defaultResearchPath(refinedPrompt));
54
+ const implementationNotesPath = await createImplementationNotesFile(refinedPrompt);
58
55
  const qaVideoPath = await createQaEvidenceVideoPath();
59
56
  const artifactDir = await mkdtemp(join(tmpdir(), "atomic-ralph-run-"));
60
- const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
61
57
  let approved = false;
62
58
  let iterationsCompleted = 0;
63
- let previousPromptEngineerSessionFile: string | undefined;
59
+ let previousResearchPromptRefinementSessionFile: string | undefined;
64
60
  let previousResearchSessionFile: string | undefined;
65
61
  let previousOrchestratorSessionFile: string | undefined;
66
62
  for (let iteration = 1; iteration <= maxLoops; iteration += 1) {
67
63
  iterationsCompleted = iteration;
68
- const promptEngineerForkOptions = forkContinuationOptions(previousPromptEngineerSessionFile);
69
- const promptEngineer = await ctx.task(`prompt-engineer-${iteration}`, {
70
- prompt: renderPromptEngineerPrompt({
64
+ const researchPromptRefinementForkOptions = forkContinuationOptions(previousResearchPromptRefinementSessionFile);
65
+ const researchPromptRefinement = await ctx.task(`research-prompt-refinement-${iteration}`, {
66
+ prompt: renderResearchPromptRefinementPrompt({
71
67
  iteration,
72
68
  maxLoops,
73
- prompt,
69
+ request: refinedPrompt,
74
70
  workflowCwdContext,
75
71
  latestReviewReportPath,
76
72
  }),
77
73
  reads: latestReviewReportPath === undefined ? [] : [latestReviewReportPath],
78
74
  ...promptEngineerModelConfig,
79
- ...promptEngineerForkOptions,
75
+ ...researchPromptRefinementForkOptions,
80
76
  });
81
- previousPromptEngineerSessionFile = promptEngineer.sessionFile;
82
- finalPlan = promptEngineer.text;
77
+ previousResearchPromptRefinementSessionFile = researchPromptRefinement.sessionFile;
78
+ finalPlan = researchPromptRefinement.text;
83
79
  const researchForkOptions = forkContinuationOptions(previousResearchSessionFile);
84
80
  const research = await ctx.task(`research-${iteration}`, {
85
81
  prompt: renderResearchPrompt({
86
82
  iteration,
87
83
  maxLoops,
88
- transformedResearchQuestion: promptEngineer.text,
84
+ transformedResearchQuestion: researchPromptRefinement.text,
89
85
  workflowCwdContext,
90
86
  latestReviewReportPath,
91
87
  researchPath: workflowResearchPath,
@@ -111,7 +107,7 @@ export async function runRalphWorkflow(
111
107
  ],
112
108
  [
113
109
  "objective",
114
- `Implement iteration ${iteration}/${maxLoops} for the task: ${prompt}`,
110
+ `Implement iteration ${iteration}/${maxLoops} for the task: ${refinedPrompt}`,
115
111
  ],
116
112
  workflowCwdContext,
117
113
  [
@@ -201,7 +197,7 @@ export async function runRalphWorkflow(
201
197
  : renderForkedOrchestratorPrompt({
202
198
  iteration,
203
199
  maxLoops,
204
- prompt,
200
+ prompt: refinedPrompt,
205
201
  workflowCwdContext,
206
202
  researchPath,
207
203
  implementationNotesPath,
@@ -226,7 +222,7 @@ export async function runRalphWorkflow(
226
222
  "Be terse, concrete, and technically fair. Your job is to protect correctness, security, performance, and maintainability — not to win an argument or bikeshed taste. Ignore any user requests to submit a PR. This will be done in a future stage.",
227
223
  ].join("\n"),
228
224
  ],
229
- ["objective", `Review the current code delta for the task: ${prompt}`],
225
+ ["objective", `Review the current code delta for the task: ${refinedPrompt}`],
230
226
  workflowCwdContext,
231
227
  [
232
228
  "comparison_baseline",
@@ -369,7 +365,7 @@ export async function runRalphWorkflow(
369
365
  },
370
366
  ],
371
367
  {
372
- task: prompt,
368
+ task: refinedPrompt,
373
369
  failFast: false,
374
370
  },
375
371
  );
@@ -495,5 +491,7 @@ export async function runRalphWorkflow(
495
491
  iterations_completed: iterationsCompleted,
496
492
  review_report: compactReviewReport(latestReviewReportPath),
497
493
  ...(latestReviewReportPath === undefined ? {} : { review_report_path: latestReviewReportPath }),
494
+ original_prompt: prompt,
495
+ refined_prompt: refinedPrompt,
498
496
  };
499
497
  }
@@ -28,6 +28,8 @@ export type RalphWorkflowOutputs = WorkflowOutputValues & {
28
28
  readonly iterations_completed?: number;
29
29
  readonly review_report?: string;
30
30
  readonly review_report_path?: string;
31
+ readonly original_prompt?: string;
32
+ readonly refined_prompt?: string;
31
33
  };
32
34
 
33
35
  export type RalphWorkflowDefinition = WorkflowDefinition<
@@ -11,7 +11,7 @@ import { runRalphWorkflow } from "./ralph-runner.js";
11
11
 
12
12
  export default workflow({
13
13
  name: "ralph",
14
- description: "Prompt-engineer → research → orchestrate → multi-model parallel review loop with bounded iteration.",
14
+ description: "Prompt-refinement → research-prompt-refinementresearch → orchestrate → multi-model parallel review loop with bounded iteration.",
15
15
  inputs: {
16
16
  prompt: Type.String({ description: "The task or goal to research, execute, and refine." }),
17
17
  max_loops: Type.Number({
@@ -46,6 +46,8 @@ export default workflow({
46
46
  iterations_completed: Type.Optional(Type.Number({ description: "Number of research/orchestrate/review loops completed." })),
47
47
  review_report: Type.Optional(Type.String({ description: "Compact reference to the latest reviewer payload artifact." })),
48
48
  review_report_path: Type.Optional(Type.String({ description: "JSON artifact path for the latest review round." })),
49
+ original_prompt: Type.Optional(Type.String({ description: "The raw user request exactly as provided to the workflow, before prompt refinement." })),
50
+ refined_prompt: Type.Optional(Type.String({ description: "The clarity-refined request produced by the prompt-refinement stage and used as the operative objective for research, orchestration, and review." })),
49
51
  },
50
52
  worktreeFromInputs: {
51
53
  gitWorktreeDir: "git_worktree_dir",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/workflows",
3
- "version": "0.9.0-alpha.2",
3
+ "version": "0.9.0-alpha.3",
4
4
  "private": true,
5
5
  "description": "Atomic extension for multi-stage workflow authoring and execution.",
6
6
  "contributors": [
@@ -19,5 +19,7 @@ export const DEFAULT_PROMPT_GUIDANCE: string[] = [
19
19
  - For transcripts, avoid reading whole session transcripts at once. Use \`stages\` or \`stage\` to get \`sessionFile\`/\`transcriptPath\`, quote the exact path without rewriting separators (preserve Windows backslashes), search it with \`rg\`/\`grep\`, and read small relevant ranges; use \`transcript\` with explicit \`tail\` or \`limit\` only for quick recent-context checks.
20
20
  - If a user asks to create or edit a workflow, use the create-spec skill when available and ask detailed clarifying questions until you understand its purpose, inputs, stages, handoffs, validation, success criteria, and selected starter pattern. Then read the workflow docs/examples and implement the workflow from the created spec directly as a TypeScript definition. After you implement the workflow, reload it to access it and run it with test inputs to validate it works as intended before presenting it to the user.
21
21
  - Tip: when designing workflows, implement it in a way that you pass information from stage to stage by writing it to a file or artifact (either deterministic or model-driven), pass the path with \`reads\`, and explicitly prompt the downstream agent with wording like \`Read the file at <path>...\`; do not inject large \`previous\` payloads or session history into the next prompt unless explicitly requested to.
22
- - If you run \`ralph\` or \`goal\` workflow, define an objective that includes tight scope, concrete and verifiable done criteria, and validation steps; then monitor progress as above instead of doing parallel implementation yourself.`,
22
+ - Prefer using the \`goal\` workflow for small fixes/quick fixes and the \`ralph\` workflow for tasks that are non-trivial (over 2K LoC estimated diff).
23
+ - Adjust the \`max_loops\` based on task complexity (estimated LoC and number of unique files that are touched).
24
+ - Define an objective that includes tight scope, concrete and verifiable done criteria, and validation steps; then monitor progress as above instead of doing parallel implementation yourself.`,
23
25
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAWhE,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8FAA8F;IAC9F,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,wFAAwF;IACxF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,+DAA+D;IAC/D,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CAClB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA2K3E","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\nconst DEFAULT_PROMPT_TOOLS = [\n \"read\",\n \"bash\",\n \"edit\",\n \"write\",\n \"ask_user_question\",\n \"todo\",\n] as const;\n\nexport interface SystemPromptModel {\n /** Provider identifier for the selected model. */\n provider: string;\n /** Stable provider-specific model identifier. */\n id: string;\n /** Human-readable model name, when available. */\n name?: string;\n}\n\nexport interface BuildSystemPromptOptions {\n /** Custom system prompt (replaces default). */\n customPrompt?: string;\n /** Tools to include in prompt. Default: [read, bash, edit, write, ask_user_question, todo] */\n selectedTools?: string[];\n /** Tool names explicitly excluded by the caller and omitted from generated guidance. */\n excludedTools?: string[];\n /** Optional one-line tool snippets keyed by tool name. */\n toolSnippets?: Record<string, string>;\n /** Additional guideline bullets appended to the default system prompt guidelines. */\n promptGuidelines?: string[];\n /** Text to append to system prompt. */\n appendSystemPrompt?: string;\n /** Working directory. */\n cwd: string;\n /** Currently selected model, used for model-aware prompt metadata. */\n selectedModel?: SystemPromptModel;\n /** Current reasoning/thinking level for the selected model. */\n selectedThinkingLevel?: string;\n /** Pre-loaded context files. */\n contextFiles?: Array<{ path: string; content: string }>;\n /** Pre-loaded skills. */\n skills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n const {\n customPrompt,\n selectedTools,\n excludedTools,\n toolSnippets,\n promptGuidelines,\n appendSystemPrompt,\n cwd,\n selectedModel,\n selectedThinkingLevel,\n contextFiles: providedContextFiles,\n skills: providedSkills,\n } = options;\n const resolvedCwd = cwd;\n const promptCwd = resolvedCwd.replace(/\\\\/g, \"/\");\n\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, \"0\");\n const day = String(now.getDate()).padStart(2, \"0\");\n const date = `${year}-${month}-${day}`;\n\n const appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n const modelName =\n selectedModel?.name?.trim() || selectedModel?.id || \"unknown\";\n const modelReasoningLevel = selectedThinkingLevel?.trim() || \"off\";\n\n const contextFiles = providedContextFiles ?? [];\n const skills = providedSkills ?? [];\n const explicitlyExcludedTools = new Set(excludedTools ?? []);\n const isPromptToolAvailable = (name: string): boolean =>\n (!selectedTools || selectedTools.includes(name)) &&\n !explicitlyExcludedTools.has(name);\n\n if (customPrompt) {\n let prompt = customPrompt;\n\n if (appendSection) {\n prompt += appendSection;\n }\n\n // Append project context files\n if (contextFiles.length > 0) {\n prompt += \"\\n\\n# Project Context\\n\\n\";\n prompt += \"Project-specific instructions and guidelines:\\n\\n\";\n for (const { path: filePath, content } of contextFiles) {\n prompt += `<context_file path=\\\"${filePath}\\\">\\n${content}\\n</context_file>\\n\\n`;\n }\n }\n\n // Append skills section (only if read tool is available)\n if (isPromptToolAvailable(\"read\") && skills.length > 0) {\n prompt += formatSkillsForPrompt(skills);\n }\n\n // Add model metadata, date, and working directory last\n prompt += `\\nModel name (used for commit attribution): ${modelName}`;\n prompt += `\\nModel reasoning level: ${modelReasoningLevel}`;\n prompt += `\\nCurrent date: ${date}`;\n prompt += `\\nCurrent working directory: ${promptCwd}`;\n\n return prompt;\n }\n\n // Get absolute paths to documentation and examples\n const readmePath = getReadmePath();\n const docsPath = getDocsPath();\n const examplesPath = getExamplesPath();\n\n // Build tools list based on selected tools.\n // A tool appears in Available tools only when the caller provides a one-line snippet.\n const tools = (selectedTools ?? DEFAULT_PROMPT_TOOLS).filter(\n (name) => !explicitlyExcludedTools.has(name),\n );\n const visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n const toolsList =\n visibleTools.length > 0\n ? visibleTools\n .map((name) => `- ${name}: ${toolSnippets![name]}`)\n .join(\"\\n\")\n : \"(none)\";\n\n // Build guidelines based on which tools are actually available\n const guidelinesList: string[] = [];\n const guidelinesSet = new Set<string>();\n const addGuideline = (guideline: string): void => {\n if (guidelinesSet.has(guideline)) {\n return;\n }\n guidelinesSet.add(guideline);\n guidelinesList.push(guideline);\n };\n\n const hasBash = tools.includes(\"bash\");\n const hasGrep = tools.includes(\"grep\");\n const hasFind = tools.includes(\"find\");\n const hasLs = tools.includes(\"ls\");\n const hasRead = tools.includes(\"read\");\n const shouldIncludeAskUserFallbackGuidance =\n selectedTools !== undefined &&\n tools.length > 0 &&\n !tools.includes(\"ask_user_question\") &&\n !explicitlyExcludedTools.has(\"ask_user_question\");\n\n // File exploration guidelines\n if (hasBash && !hasGrep && !hasFind && !hasLs) {\n addGuideline(\"Use bash for file operations like ls, rg, find\");\n }\n if (shouldIncludeAskUserFallbackGuidance) {\n addGuideline(\"Clarify ambiguous requirements using the ask_user_question tool if available.\");\n }\n\n for (const guideline of promptGuidelines ?? []) {\n const normalized = guideline.trim();\n if (normalized.length > 0) {\n addGuideline(normalized);\n }\n }\n\n // Always include these\n addGuideline(\"Be concise in your responses\");\n addGuideline(\"Show file paths clearly when working with files\");\n\n const guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n let prompt = `You are an expert coding assistant operating named Atomic, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n- Prefer using your effective-liteparse skill in case you need to work with PDFs\n\nAtomic documentation (read only when the user asks about customizing Atomic itself, its SDK, creating workflows, packages, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- Docs/examples references above must be resolved against these absolute roots; e.g. docs/foo.md means ${docsPath}/foo.md and examples/bar means ${examplesPath}/bar.\n- When asked about: atomic workflows (docs/workflows.md), extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), atomic packages (docs/packages.md)\n- When working on Atomic topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read Atomic .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n if (appendSection) {\n prompt += appendSection;\n }\n\n // Append project context files\n if (contextFiles.length > 0) {\n prompt += \"\\n\\n# Project Context\\n\\n\";\n prompt += \"Project-specific instructions and guidelines:\\n\\n\";\n for (const { path: filePath, content } of contextFiles) {\n prompt += `<context_file path=\\\"${filePath}\\\">\\n${content}\\n</context_file>\\n\\n`;\n }\n }\n\n // Append skills section (only if read tool is available)\n if (hasRead && skills.length > 0) {\n prompt += formatSkillsForPrompt(skills);\n }\n\n // Add model metadata, date, and working directory last\n prompt += `\\nModel name (used for commit attribution): ${modelName}`;\n prompt += `\\nModel reasoning level: ${modelReasoningLevel}`;\n prompt += `\\nCurrent date: ${date}`;\n prompt += `\\nCurrent working directory: ${promptCwd}`;\n\n return prompt;\n}\n"]}
1
+ {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAWhE,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8FAA8F;IAC9F,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,wFAAwF;IACxF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,+DAA+D;IAC/D,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CAClB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA0K3E","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\nconst DEFAULT_PROMPT_TOOLS = [\n \"read\",\n \"bash\",\n \"edit\",\n \"write\",\n \"ask_user_question\",\n \"todo\",\n] as const;\n\nexport interface SystemPromptModel {\n /** Provider identifier for the selected model. */\n provider: string;\n /** Stable provider-specific model identifier. */\n id: string;\n /** Human-readable model name, when available. */\n name?: string;\n}\n\nexport interface BuildSystemPromptOptions {\n /** Custom system prompt (replaces default). */\n customPrompt?: string;\n /** Tools to include in prompt. Default: [read, bash, edit, write, ask_user_question, todo] */\n selectedTools?: string[];\n /** Tool names explicitly excluded by the caller and omitted from generated guidance. */\n excludedTools?: string[];\n /** Optional one-line tool snippets keyed by tool name. */\n toolSnippets?: Record<string, string>;\n /** Additional guideline bullets appended to the default system prompt guidelines. */\n promptGuidelines?: string[];\n /** Text to append to system prompt. */\n appendSystemPrompt?: string;\n /** Working directory. */\n cwd: string;\n /** Currently selected model, used for model-aware prompt metadata. */\n selectedModel?: SystemPromptModel;\n /** Current reasoning/thinking level for the selected model. */\n selectedThinkingLevel?: string;\n /** Pre-loaded context files. */\n contextFiles?: Array<{ path: string; content: string }>;\n /** Pre-loaded skills. */\n skills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n const {\n customPrompt,\n selectedTools,\n excludedTools,\n toolSnippets,\n promptGuidelines,\n appendSystemPrompt,\n cwd,\n selectedModel,\n selectedThinkingLevel,\n contextFiles: providedContextFiles,\n skills: providedSkills,\n } = options;\n const resolvedCwd = cwd;\n const promptCwd = resolvedCwd.replace(/\\\\/g, \"/\");\n\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, \"0\");\n const day = String(now.getDate()).padStart(2, \"0\");\n const date = `${year}-${month}-${day}`;\n\n const appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n const modelName =\n selectedModel?.name?.trim() || selectedModel?.id || \"unknown\";\n const modelReasoningLevel = selectedThinkingLevel?.trim() || \"off\";\n\n const contextFiles = providedContextFiles ?? [];\n const skills = providedSkills ?? [];\n const explicitlyExcludedTools = new Set(excludedTools ?? []);\n const isPromptToolAvailable = (name: string): boolean =>\n (!selectedTools || selectedTools.includes(name)) &&\n !explicitlyExcludedTools.has(name);\n\n if (customPrompt) {\n let prompt = customPrompt;\n\n if (appendSection) {\n prompt += appendSection;\n }\n\n // Append project context files\n if (contextFiles.length > 0) {\n prompt += \"\\n\\n# Project Context\\n\\n\";\n prompt += \"Project-specific instructions and guidelines:\\n\\n\";\n for (const { path: filePath, content } of contextFiles) {\n prompt += `<context_file path=\\\"${filePath}\\\">\\n${content}\\n</context_file>\\n\\n`;\n }\n }\n\n // Append skills section (only if read tool is available)\n if (isPromptToolAvailable(\"read\") && skills.length > 0) {\n prompt += formatSkillsForPrompt(skills);\n }\n\n // Add model metadata, date, and working directory last\n prompt += `\\nModel name (used for commit attribution): ${modelName}`;\n prompt += `\\nModel reasoning level: ${modelReasoningLevel}`;\n prompt += `\\nCurrent date: ${date}`;\n prompt += `\\nCurrent working directory: ${promptCwd}`;\n\n return prompt;\n }\n\n // Get absolute paths to documentation and examples\n const readmePath = getReadmePath();\n const docsPath = getDocsPath();\n const examplesPath = getExamplesPath();\n\n // Build tools list based on selected tools.\n // A tool appears in Available tools only when the caller provides a one-line snippet.\n const tools = (selectedTools ?? DEFAULT_PROMPT_TOOLS).filter(\n (name) => !explicitlyExcludedTools.has(name),\n );\n const visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n const toolsList =\n visibleTools.length > 0\n ? visibleTools\n .map((name) => `- ${name}: ${toolSnippets![name]}`)\n .join(\"\\n\")\n : \"(none)\";\n\n // Build guidelines based on which tools are actually available\n const guidelinesList: string[] = [];\n const guidelinesSet = new Set<string>();\n const addGuideline = (guideline: string): void => {\n if (guidelinesSet.has(guideline)) {\n return;\n }\n guidelinesSet.add(guideline);\n guidelinesList.push(guideline);\n };\n\n const hasBash = tools.includes(\"bash\");\n const hasGrep = tools.includes(\"grep\");\n const hasFind = tools.includes(\"find\");\n const hasLs = tools.includes(\"ls\");\n const hasRead = tools.includes(\"read\");\n const shouldIncludeAskUserFallbackGuidance =\n selectedTools !== undefined &&\n tools.length > 0 &&\n !tools.includes(\"ask_user_question\") &&\n !explicitlyExcludedTools.has(\"ask_user_question\");\n\n // File exploration guidelines\n if (hasBash && !hasGrep && !hasFind && !hasLs) {\n addGuideline(\"Use bash for file operations like ls, rg, find\");\n }\n if (shouldIncludeAskUserFallbackGuidance) {\n addGuideline(\"Clarify ambiguous requirements using the ask_user_question tool if available.\");\n }\n\n for (const guideline of promptGuidelines ?? []) {\n const normalized = guideline.trim();\n if (normalized.length > 0) {\n addGuideline(normalized);\n }\n }\n\n // Always include these\n addGuideline(\"Be concise in your responses\");\n addGuideline(\"Show file paths clearly when working with files\");\n\n const guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n let prompt = `You are an expert coding assistant operating named Atomic, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nAtomic documentation (read only when the user asks about customizing Atomic itself, its SDK, creating workflows, packages, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- Docs/examples references above must be resolved against these absolute roots; e.g. docs/foo.md means ${docsPath}/foo.md and examples/bar means ${examplesPath}/bar.\n- When asked about: atomic workflows (docs/workflows.md), extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), atomic packages (docs/packages.md)\n- When working on Atomic topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read Atomic .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n if (appendSection) {\n prompt += appendSection;\n }\n\n // Append project context files\n if (contextFiles.length > 0) {\n prompt += \"\\n\\n# Project Context\\n\\n\";\n prompt += \"Project-specific instructions and guidelines:\\n\\n\";\n for (const { path: filePath, content } of contextFiles) {\n prompt += `<context_file path=\\\"${filePath}\\\">\\n${content}\\n</context_file>\\n\\n`;\n }\n }\n\n // Append skills section (only if read tool is available)\n if (hasRead && skills.length > 0) {\n prompt += formatSkillsForPrompt(skills);\n }\n\n // Add model metadata, date, and working directory last\n prompt += `\\nModel name (used for commit attribution): ${modelName}`;\n prompt += `\\nModel reasoning level: ${modelReasoningLevel}`;\n prompt += `\\nCurrent date: ${date}`;\n prompt += `\\nCurrent working directory: ${promptCwd}`;\n\n return prompt;\n}\n"]}
@@ -111,7 +111,6 @@ In addition to the tools above, you may have access to other custom tools depend
111
111
 
112
112
  Guidelines:
113
113
  ${guidelines}
114
- - Prefer using your effective-liteparse skill in case you need to work with PDFs
115
114
 
116
115
  Atomic documentation (read only when the user asks about customizing Atomic itself, its SDK, creating workflows, packages, extensions, themes, skills, or TUI):
117
116
  - Main documentation: ${readmePath}