Act-Driven Workflows (ADW)
All the world’s a stage, and all the men and women merely players; they have their exits and their entrances, and one man in his time plays many parts.
— William Shakespeare, As You Like It
While Guidance-Driven Processing (GDP) excels at handling localized, in-context file operations using marginalia (@guidance tags), modern software development often demands standardizing AI operations across entire projects, directories, or team boundaries.
This is where Act-Driven Workflows (ADW) come in. ADW transitions your automation from individual, file-bound instructions (micro-level) to global, reusable, and structured execution blueprints (macro-level). In this paradigm, an Act is your script, and Ghostwriter is the seasoned actor executing your vision flawlessly every single time.
What is an Act?
An Act is a saved, reusable Ghostwriter workflow, defined once in a TOML file. Its configuration supplies instructions for the AI, one or more prompts, optional file-selection settings, and the specific tools the AI is allowed to use. Instead of writing complex, repetitive prompt instructions every time you need the AI to perform a task, you select a pre-configured Act—such as task, code-doc, unit-tests, or sonar-fix—provide an optional short request, and let Ghostwriter orchestrate the entire workflow.
Under the hood, ActProcessor loads and merges the TOML configuration (including any inherited parent Act), prepares the request and its episodes, and hands each prompt to AIFileProcessor. That processor supplies project and file context, loads the permitted tools, expands any included content, and calls the configured AI provider. This layering is what makes Acts suitable for routine, repeatable work: documentation generation, test creation, reviewing static-analysis findings, or a carefully scoped custom task.
If no Act is named on the command line, Ghostwriter falls back to the help Act.
| GDP (Micro-Level) | ADW (Macro-Level) |
|---|---|
| • Embedded in code comments | • Declared in TOML files |
| • Tied to specific files | • Globally reusable |
| • Great for single-file sync | • Great for project tasks |
Without an Act, standardizing a task across your team means pasting long instructions into a chat window:
"Please look through this project's source code, find all the public classes and methods that are missing documentation, and add clear comments explaining what they do, without changing any logic."
With an Act, the entire process is reduced to a single command:
--act code-doc
The result is identical, execution is highly consistent, and the entire team benefits from the same standardized recipe.
Core Capabilities of an Act
Acts do more than just wrap prompts. They act as declarative pipelines capable of:
- Targeting Context Dynamically: Running across an entire multi-module project, a single module, a specific folder, or scoped using file globbing patterns.
- Providing sensible defaults: Running autonomously out-of-the-box, even if no extra arguments are specified, via a
[default]fallback block. - Supporting Inheritance: Reusing, extending, or overriding existing Acts (including built-in ones) with
basedOn, to prevent duplication. - Enabling Stateful Execution: Running as a quick "one-time" batch command or starting an interactive, multi-turn chat session.
- Filtering Tool Access: Restricting exactly which tools the AI may call for a given prompt, using regular-expression patterns.
- Orchestrating Complex Pipelines: Chaining together multiple sub-prompts (episodes) with unique model configurations and active tool subsets.
How to Run an Act
The basic CLI execution syntax is:
--act <act-name> [optional request text]
Any request text you type after the Act name becomes the user's prompt, made available to the TOML template as ${public.prompt}.
Examples in Action:
# Get help or look up usage
--act help
# General task execution
--act task "Explain this project's module structure"
# Documenting codebase
--act code-doc "Add missing Javadocs for org.machanism.core"
# Generating testing suites
--act unit-tests "Improve coverage for parser classes"
- With request text: Ghostwriter appends your specific query to the Act's built-in instructions.
- Without request text: Ghostwriter falls back to the configured default prompt (
default.public.prompt, if the Act defines one) or awaits your interactive input.
Note: Defaults are applied before your typed request is bound to
public.prompt. If an Act already definesdefault.public.promptand no other value has been supplied, that default is what the template uses—your appended request text does not silently overwrite it unless the Act is written to expect it. See Default Prompt Handling below.
Quick Shortcut: >
To run a general-purpose instruction without explicitly selecting an Act, use the > prefix (this is a fast shorthand for the default task Act):
--act > "summarize the latest project changes"
> summarize the latest project changes is treated exactly as task summarize the latest project changes.
Execution Modes & Multi-Step Pipelines
Acts support two execution modes and can be broken down into structured steps (episodes).
1. One-Time vs. Interactive Modes
- Non-Interactive (Batch): Excellent for CI/CD pipelines. Ghostwriter runs the Act once, writes the changes, and terminates.
bash
--act code-doc "Add Javadoc to this package"
- Interactive (Chat): Opens a real-time conversational interface. You can review changes, request modifications, or ask follow-up questions. Set
interactive = trueunder[gw]to enable this mode.
bash
--act help
During interactive sessions, use these fast terminal commands:
| Command | Action |
|---|---|
. |
Ends the conversation and finalizes the Act execution. |
> |
Accepts the AI's last output and continues to the next phase without sending a new text message. |
>> |
Accepts the AI's last output and switches all remaining work to non-interactive processing. |
| (anything else) | Sent as the next chat prompt. |
An empty entry has no special meaning by itself; if your environment forwards it, it's treated as ordinary follow-up input rather than as a continue or exit command.
2. Multi-Step Acts (Episodes)
Complex workflows often require a series of logical steps: first analyzing, then editing, and finally verifying. Each ordered prompt in that sequence is called an episode. An Act's inputs value can be a single string (one default prompt) or a TOML array of strings, where each array entry becomes its own episode.
By default, all episodes run sequentially. However, you can surgically execute specific steps using the # syntax:
# Run only step 1 and step 2 of the "review" Act
--act review#1,2 "Check error handling"
# Run steps 1 and 2, then immediately terminate without running subsequent steps
--act review#1,2!
Without !, the requested episodes run and normal sequential ordering may then continue. An episode can also programmatically request a jump to a different episode while it is being processed, allowing workflows to branch based on what the AI finds.
Anatomy of an Act File (.toml)
Acts are defined in TOML (Tom's Obvious, Minimal Language)—a highly readable, key-value configuration format.
Act Locations
Ghostwriter looks for Acts in the following order:
- Built-in Acts: Classpath resources under
/acts/, included out of the box. - Local Custom Acts: Loaded from a configured project acts directory (allowing you to override built-ins by matching their names). Relative locations are resolved from the project root.
- Remote Acts: Loaded via HTTP/HTTPS URLs or direct local file paths.
You can also pass an absolute path to a TOML file directly as the Act name—for example, C:\work\acts\my-review.toml. In that case, the classpath-resource hierarchy and built-in lookup are bypassed entirely for that file.
Building Blocks of a TOML Act
Here is a comprehensive overview of how an Act file is structured:
description = '''
Reviews project documentation and suggests structural improvements.
'''
# Behind-the-scenes system guidance telling the AI how to behave
instructions = '''
You are an expert technical writer. Review documentation for clarity, precision, and readability.
'''
# The prompt payload sent to the AI
inputs = '''
# Task
Review the documentation in this project and suggest structural improvements.
${public.prompt}
'''
# Fallback values if not provided via the command line
[default]
public.prompt = "Focus on files that might confuse new developers."
# Technical settings controlling file targeting and execution mode
[gw]
path = "glob:src/site/**"
interactive = true
threads = 4
excludes = ["**/target/**", "**/node_modules/**"]
instructions provide stable, system-level guidance and rarely change between runs. inputs hold the prompt(s) actually sent to the AI. [gw] settings configure Ghostwriter behavior itself—path, interactive, threads, excludes, and nonRecursive are the common keys. Any other string values you place under [default] are made available for substitution through the configurator.
Placeholders & Dynamic Substitution (${...})
Placeholders act as variables populated at runtime. Examples include:
${public.prompt}— The text query typed by the user in the CLI, or the resolved default.${public.projectName}— The resolved name of the project folder.${sonar.host}/${sonar.token}— Environment variables or configuration parameters.${super.value}— The inherited value from a parent Act (see Inheritance).
⚠️ Critical Rule for AI Assistants: When editing or generating Act files, never substitute, resolve, or hardcode values for placeholders like
${public.prompt}. Leave them exactly in their${...}syntax—Ghostwriter, its configurator, and its functional tools resolve them dynamically at runtime.
Prompt Front Matter & Tool Filtering
Any individual inputs entry (whether it's the whole prompt or one episode in an array) may start with YAML front matter between --- lines. This is where you control the model and the exact tools available for that specific prompt:
inputs = '''
---
gw.model: ${public.reviewModel}
enabledTools:
- org.machanism.machai.gw.tools.ProjectContextFunctionTools:get_project_context_variable
- org\.machanism\..*:read_file
---
Inspect ${public.prompt}.
'''
gw.modelselects a model/provider for that prompt specifically, overriding any act-level default.enabledToolsaccepts either a YAML list or a whitespace-, comma-, or semicolon-separated string. Each item is a regular-expression pattern.
Internally, every tool has a fully qualified identifier in the format <ClassName>:<toolName>—for example, org.example.Tools:read_file (the tool name is its declared name, or the method name when none is explicitly set). A tool is registered for that prompt only when its identifier matches at least one supplied pattern. If enabledTools is omitted entirely, all available tools are registered without filtering—so use precise patterns whenever an Act should have deliberately limited capabilities.
Including External Files (>>>)
To keep instructions DRY (Don't Repeat Yourself), you can import external markdown files or remote guidelines using the triple-chevron syntax—this works in both instructions and inputs, and is processed recursively:
>>> file://docs/shared-corporate-rules.md
>>> https://example.com/team-standards.md
Advanced: Inheritance (basedOn)
You can inherit settings and instructions from a parent Act, modifying only what you need:
basedOn = "task"
instructions = '''
${super.value}
Additionally, strictly enforce Python PEP 8 styling rules.
'''
Here's what actually happens during the merge: the child file is read first, then its basedOn parent is loaded into the same property map. Wherever the child already defines a value, that value wins as the "override"—but if the override string contains ${super.value}, that placeholder is replaced with the inherited value from the parent; without the placeholder, the child's value is used as-is. For inputs arrays, inheritance is positional: an episode containing ${super.value} pulls in the corresponding parent episode, and any extra episodes beyond the parent's array are simply kept.
[default] entries follow a similar, gentler rule: a default.some.key value is copied to some.key only when no non-default value already exists for it—an actual configured value always takes precedence over a default.
In short: use basedOn for reusable templates, ${super.value} to preserve or extend inherited/configured content, and [default] for values that should only apply when nothing else was set. A local custom Act sharing a name with a built-in Act is loaded the same way, letting you override or extend the bundled definition.
Default Prompt Handling (public.prompt)
The prompt property an Act actually uses is the dotted TOML key public.prompt—there is no separate top-level prompt key. Define default.public.prompt to supply a request the template should fall back to when nothing else has set it:
[default]
public.prompt = "Review the project for documentation gaps."
inputs = '''
Perform this request: ${public.prompt}
'''
Important precedence rule: defaults are applied before the request text you type after the Act name is bound. So if an Act defines default.public.prompt, that default is retained unless public.prompt is supplied through configuration some other way—your appended CLI text does not automatically replace it. If you're authoring an Act that must react to whatever text the user types after its name, don't define a competing default.public.prompt; instead, let the caller set public.prompt explicitly.
Step-by-Step: Create and Run Your First Act
Let's build a custom documentation audit Act.
Step 1: Create the TOML File
In your configured custom Acts folder, create a file named doc-audit.toml.
Step 2: Write the Blueprint
Paste the following configuration into the file:
description = '''
Audits markdown files for stylistic errors, passive voice, and formatting issues.
'''
instructions = '''
You are a meticulous copyeditor. Analyze the provided text for grammatical strength, avoiding passive voice, and maintaining markdown structure.
'''
inputs = '''
---
enabledTools:
- org\.machanism\..*:read_file
---
# Markdown Style Audit
Please audit the markdown files in the specified path. Highlight any dense text blocks, passive verbs, or broken formatting.
Specific Focus: ${public.prompt}
'''
[default]
public.prompt = "Check readability score and active verb usage."
[gw]
path = "glob:**/*.md"
interactive = true
Step 3: Run the Act
Execute your newly created Act using the default settings:
--act doc-audit
Or run it with a customized scope:
--act doc-audit "Scan the API reference pages specifically"
Once executed, Ghostwriter will isolate the markdown files, feed them into the context window, and open an interactive chat session so you can fine-tune the resulting edits—use > to continue, >> to finish the rest non-interactively, or . to stop.
Built-in Acts Reference
| Act | What it does |
|---|---|
code-doc |
Adds or improves documentation comments (Javadoc, docstrings, etc.) in code files. Limited strictly to documentation changes and ignores .machai. |
commit |
Analyzes pending Git or SVN changes, groups them into logical commits, writes messages matching repository style, and executes the commits. Runs interactively with command tools. |
grype-fix |
Uses Syft and Grype scan output to find dependency vulnerabilities, updates affected dependencies, builds the Maven project, and documents the remediation. |
help |
Provides interactive help for finding and understanding Acts and episodes, including inheritance and invocation. |
sonar-fix |
Retrieves SonarQube findings, fixes eligible quality/security issues, adds or updates tests, validates the build, and records changed files. Does not alter SonarQube configuration or quality gates. |
task |
The minimal, general-purpose, project-aware assistant workflow. Selected automatically by the > shorthand. |
unit-tests |
Builds the project, analyzes JaCoCo coverage, and creates or improves unit tests for under-covered code. |
Quick Reference Sheet
Command Cheatsheet
# General Execution
--act <act-name> [request text]
# Quick task shorthand (runs the 'task' Act)
--act > <your-quick-task>
# Run specific steps (episodes) of an Act
--act <act-name>#1,3
# Run specific steps and stop immediately
--act <act-name>#1,3!
# Run an Act directly from an absolute TOML file path
--act C:\work\acts\my-review.toml
Interactive Terminal Commands
| Input | Action |
|---|---|
. |
Complete the current session and write changes. |
> |
Proceed to the next step/accept AI output without adding user text. |
>> |
Accept AI output and finish remaining work non-interactively. |
Common [gw] TOML Keys (Act-Level)
| Key | Type | Description |
|---|---|---|
path |
string |
Glob or folder path targeting the files to analyze. |
interactive |
boolean |
Determines if the Act runs in batch mode or opens an interactive chat. |
threads |
int |
Number of concurrent threads used for processing files. |
excludes |
array |
Glob patterns of directories/files to bypass. |
nonRecursive |
boolean |
If true, stops Ghostwriter from descending into subdirectories. |
Prompt Front Matter Keys (Per-Episode Overrides)
| Key | Type | Description |
|---|---|---|
gw.model |
string |
Overrides the AI model/provider for this specific prompt only. |
enabledTools |
string or array |
Regular-expression patterns matched against <ClassName>:<toolName> to filter which tools this prompt may call. Omit to allow all tools. |