Skip to content

Commit b93cade

Browse files
authored
Workflows (#46)
1 parent b6bf67e commit b93cade

File tree

14 files changed

+795
-61
lines changed

14 files changed

+795
-61
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
Let's implement and document a new feature:
2+
3+
# Feature Description (Workflows)
4+
5+
The task description entered by the user may include lines starting with /
6+
7+
These are considered "workflow commands". They correspond to user-defined programs or shell scripts placed in the `.agents/workflows` directory of the repository under which `get-task` is executed. When `get-task` is executed, it looks for such workflow commands in the task description. For each such command, the matching programs is executed and its output is inserted in the place of the workflow command in the final text printed to `stdout` by `get-task` (a good analogy for this would be a macro in a programming language).
8+
9+
The workflow command line may feature parameters. These should be parsed in the same way bash would parse them (i.e. `/some-workflow 10 "foo bar"` would mean two parameters, the second one being a string).
10+
11+
Instead of a workflow program, in the `.agents/workflows` dir there might be a simple txt file named `<workflow-command>.txt`. In this case, the contents of this file are inserted as a verbatim copy in the place of the workflow command.
12+
13+
In the output of each workflow command, there might be special lines such as "@agents-setup FOO=x BAR=10". Such lines indicate ENV variables that will be set in the environment by scripts such as `codex-setup`, `jules-setup`, etc, before the matching user-defined setup script from the `.agents` directory of the target repository are executed. The lines are stripped from the regular `get-task` output.
14+
15+
The command `get-task --get-setup-env` lists all such ENV vars with their assignments from all @agents-setup directives that ended up in the task description (both inserted by the user directly and inserted by workflow commands). The `agents-workflow/***-setup` scripts use this command to set up the environment.
16+
17+
## Validation of the task description
18+
19+
After the user enters the task description (the EDITOR executed by `agent-task` quits with exit code 0), we would validate the entered task description. Any referenced workflows that don't have a matching definitions under `.agents/workflows` will be reported as errors. Conflicting variable assignments from `@agents-setup` directives will be reported as errors as well.
20+
21+
If some of workflow commands exit with a non-zero exit code, their `stderr` is included in a diagnostic message like this:
22+
23+
Failure in executing workflow commands:
24+
$ foo 10
25+
<stderr contents>
26+
$ bar
27+
<stderr contents>
28+
29+
If the workflow command script exists, but it's not executable, try to automatically make it executable on platforms where this is possible. If this was not successful, report this with an appropriate diagnostic message.
30+
31+
The error are reported by printing all diagnostic messages on the screen and asking the user to press any key to continue or Ctrl+C to abort. If the user continues, the editor is launched again, allowing the user to correct the issues.
32+
33+
If the task description is directly supplied on the command line with `--prompt` or `--prompt-file`, `agent-task` reports the same diagnostic messages and exits with non-zero exit code.
34+
35+
# Tasks
36+
37+
* Implement the new features
38+
39+
* Provide comprehensive user-facing documentation in the README.
40+
41+
* Add tests for all of the described functionality. Make sure to test the happy path for shell scripts and ruby programs as workflow commands, as well as with txt files. Make sure to have tests for the correct production of error massages in all possible modes (interactive, --prompt, --prompt-file). Make sure to add test cases for all possible diagnostic message conditions.
42+
43+
* Add a test case that setups a new temp repo that features setup scripts in its `.agents` directory. Simulate running scripts such as `agents-workflow/codex-setup`, `agents-workflow/jules-setup`, etc, when the CWD is set to the temp repository and verify that env vars provided with @agents-setup directives in the task description will be properly loaded and forwarded to the setup scripts from the temp repo. Please note that the `agents-workflow` repo will be moved as a result of calling the setup script, so invoke the setup command with a fresh local clone of the agents-workflow repo for each test or suppress the moving logic for most tests (keep at least one test that enables the logic though).
44+
45+
--- FOLLOW UP TASK ---
46+
Please implement all test cases described near the end of .agents/tasks/2025/07/01-1348-workflows. Think of any additional test cases that would cover all of the described functionality.
47+
48+
--- FOLLOW UP TASK ---
49+
Let's improve the test cases for the workflows feature:
50+
51+
1) There is no need to have multiple test files. You can combine them into one, but don't delete any test.
52+
2) I'd like some of tests to involve more then one workflow commands.
53+
3) I'd like some of the task descriptions to be longer, where the workflow command appears as a first line, as a last line (with or without a trailing whitespace), in the middle of the text, with trailing whitespace on the line, etc.
54+
4) I'd like to see some workflow commands accepting parameters. Make sure some of the parameters are strings that contain spaces.
55+
56+
--- FOLLOW UP TASK ---
57+
In the tests folder, use indented heredoc strings instead of single-line strings with "\n" characters in order to make the code easier to read.
58+
59+
--- FOLLOW UP TASK ---
60+
Helpers like are now defined in multiple places. Refactor the code to use a single definition (probably a regular global function). There are similar helpers for Linux and macOS. They should all be in a single place.
61+
--- FOLLOW UP TASK ---
62+
Helpers like `windows?` are now defined in multiple places. Refactor the code to use a single definition (probably a regular global function). There are similar helpers for Linux and macOS. They should all be in a single place.

README.md

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,68 @@
11
## Overview
22

3-
This repository provides an opinionated workflow designed to
4-
enhance the performace of teams working with coding agents,
5-
such as OpenAI Codex, Claude Code, Google Jules, GitHub Copilot,
6-
Goose, OpenHands and others.
3+
This repository provides a highly-opinionated workflow for working
4+
with cloud and local coding agents, such as Claude Code, Codex, GitHub
5+
Copilot, Jules, Gemini, Goose, OpenHands and others.
76

8-
The workflow standardizes how tasks are defined, and tracked,
9-
leveraging your VCS (e.g. git) as the primary driving interface.
7+
## Goals
108

11-
## Purpose
9+
The workflow adheres to the following principles, which are implemened
10+
both when workign with local agents and when working with remote agents:
1211

13-
The primary goal of this workflow is to:
12+
1. **The developer provides a coding task through a convenient command-line interface**
1413

15-
1. **Use git as the primary interface for driving Codex:**
14+
3. **The agent works in a secure sandbox environment, without asking for confirmation when using tools**
1615

17-
Provides a convenient way to assign tasks to Codex right
18-
from your command-line.
16+
4. **The agent presents a complete patch/PR once it reaches a stage where all tests and linters are green**
1917

20-
2. **Maintain a transparent history:**
18+
5. **It's easy to start multiple tasks in parallel from the current state of your working tree**
2119

22-
All task descriptions are committed to Git, creating an
23-
auditable trail and a knowledge base demonstrating how
24-
tasks are approached and solved.
20+
6. **All tasks are recorded as commits/files in the history of the project**
2521

26-
This allows team members to learn from each other's practices
27-
and makes `git blame` an effective tool for understanding the
28-
intention behind all code. The workflow injects instructions
29-
that teach the agents how to leverage this.
22+
Pushing to git becomes the primary interface for starting cloud agents.
23+
All other interactions with the web UIs of the agents are automated.
3024

31-
3. **Deal with the current limitations around internet connectivity:**
25+
Committing all task descriptions in git creates an auditable trail and
26+
a knowledge base demonstrating how tasks are approached and solved.
3227

33-
By pre-fetching internet resources mentioned in the task
34-
descriptions, agents such as Codex are more successful at
35-
dealing with problems that require information that is not
36-
part of the codebase.
28+
This allows team members to learn from each other's practices and makes
29+
`git blame` an effective tool for understanding the intention behind all
30+
code. The workflow injects instructions that teach the agents how to
31+
leverage this.
3732

38-
4. **Simplify the agents workspace setup:**
33+
Local agents are started is devcontainers with rich support for different
34+
interaction patterns:
3935

40-
The `.agents/codex-setup` script is stored in your repository,
41-
simplifying the maintainance of the workspace.
36+
- Start one Editor/IDE instance per task to observe the work of the agent
37+
and review the final
38+
39+
- Push to a designated branch automatically or create a PR.
40+
41+
## Other Practical Benefits
42+
43+
* Local agents can leverage ZFS and Btrfs snapshots to provide the best
44+
possible agent-start up time. The agent takes advantage of incremental
45+
compilation when building the project and its test suite.
46+
47+
* The same start-up time and incremental compilations are possible when
48+
you dispatch the coding tasks to a cluster of self-managed machines in
49+
an office environment or a private cloud.
50+
51+
* The workflow smooths out the differences between different agent tools
52+
and cloud environments. Everything can be handled through shared config
53+
and user interfaces.
54+
55+
The behavior of the cloud agents is modified through prompt engineering
56+
and automation to implement new workflows such as automatically creating
57+
PRs, automatically pushing to specific branches, etc.
58+
59+
* The workflow provides a helpful framework for automatically downloading
60+
relevant internet resources before coding tasks start for agents that
61+
need to operate offline.
62+
63+
* The workflow provides a framework for working in big monorepos that speeds
64+
up agent start-up times (both locally and it the cloud) and helps with
65+
managing the context of the agent in such repositories.
4266

4367
## Using the Workflow
4468

@@ -84,6 +108,46 @@ The primary goal of this workflow is to:
84108
The `get-task` script will print the task description for the agent,
85109
along with instructions for accessing the downloaded internet resources
86110
and working with the git history.
111+
It also supports a `--get-setup-env` option which prints only the
112+
environment variable assignments gathered from `@agents-setup` lines.
113+
114+
### Workflow Commands
115+
116+
Task descriptions may include lines beginning with `/` (e.g. `/front-end-task`).
117+
118+
When `get-task` is executed, these lines are replaced with the output of a
119+
matching programs or text files in the `.agents/workflows` folder of your
120+
repository.
121+
122+
In other words, in the example above, `get-task` will look either for an
123+
executable stored in `.agents/workflows/front-end-task` or for a text file
124+
located at `.agents/workflows/front-end-task.txt` (the contents of this file
125+
will take the place of the workflow command in the task description, like a
126+
macro in a programming language).
127+
128+
Executables are typically used when the workflow command has parameters.
129+
130+
Lines starting with `@agents-setup` in either the task file or the workflow
131+
output are stripped from the final message and interpreted as environment
132+
variable assignments for the `*-setup` scripts described below.
133+
134+
```shell
135+
@agent-setup DEV_SHELL=csharp TESTED_COMPONENTS+=backend,db
136+
```
137+
138+
A directive may either assign a value (`VAR=value`) or append entries to a
139+
comma‑separated set using the `VAR+=val1,val2` syntax. When multiple directives
140+
affect the same variable, the following rules apply:
141+
142+
1. Conflicting direct assignments (different values for the same variable)
143+
result in an error.
144+
2. A direct assignment can be combined with one or more appends. The final value
145+
contains the assigned value plus all appended entries, regardless of their
146+
order.
147+
3. One or more append operations without a direct assignment simply combine
148+
their entries.
149+
150+
Duplicate directives or values are ignored.
87151

88152
## Supported Agent Systems
89153

codex-setup

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ EOF
4848

4949
bash "$AGENTS_WORKFLOW_DIR/common-pre-setup"
5050

51+
SETUP_ENV="$("$AGENTS_WORKFLOW_DIR/bin/get-task" --get-setup-env 2>/dev/null)"
52+
if [ -n "$SETUP_ENV" ]; then
53+
while IFS= read -r line; do
54+
export "$line"
55+
done <<< "$SETUP_ENV"
56+
fi
57+
5158
if [ -f .agents/codex-setup ]; then
5259
.agents/codex-setup
5360
fi

copilot-setup

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ AGENTS_WORKFLOW_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
44

55
bash "$AGENTS_WORKFLOW_DIR/common-pre-setup"
66

7+
SETUP_ENV="$("$AGENTS_WORKFLOW_DIR/bin/get-task" --get-setup-env 2>/dev/null)"
8+
if [ -n "$SETUP_ENV" ]; then
9+
while IFS= read -r line; do
10+
export "$line"
11+
done <<< "$SETUP_ENV"
12+
fi
13+
714
if [ -f .agents/copilot-setup ]; then
815
.agents/copilot-setup
916
fi

goose-setup

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ AGENTS_WORKFLOW_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
44

55
bash "$AGENTS_WORKFLOW_DIR/common-pre-setup"
66

7+
SETUP_ENV="$("$AGENTS_WORKFLOW_DIR/bin/get-task" --get-setup-env 2>/dev/null)"
8+
if [ -n "$SETUP_ENV" ]; then
9+
while IFS= read -r line; do
10+
export "$line"
11+
done <<< "$SETUP_ENV"
12+
fi
13+
714
if [ -f .agents/goose-setup ]; then
815
.agents/goose-setup
916
fi

jules-setup

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ AGENTS_WORKFLOW_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
44

55
bash "$AGENTS_WORKFLOW_DIR/common-pre-setup"
66

7+
SETUP_ENV="$("$AGENTS_WORKFLOW_DIR/bin/get-task" --get-setup-env 2>/dev/null)"
8+
if [ -n "$SETUP_ENV" ]; then
9+
while IFS= read -r line; do
10+
export "$line"
11+
done <<< "$SETUP_ENV"
12+
fi
13+
714
if [ -f .agents/jules-setup ]; then
815
.agents/jules-setup
916
fi

lib/agent_task/cli.rb

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,9 @@ def run_get_task(args = [])
266266
opts.on('--autopush', 'Tells the agent to automatically push its changes') do
267267
options[:autopush] = true
268268
end
269+
opts.on('--get-setup-env', 'Print ENV vars from @agents-setup directives') do
270+
options[:get_setup_env] = true
271+
end
269272
end.parse!(args)
270273

271274
repos = discover_repos
@@ -275,17 +278,28 @@ def run_get_task(args = [])
275278
end
276279

277280
if repos.length == 1 && repos[0][0].nil?
278-
puts repos[0][1].agent_prompt_with_autopush_setup(autopush: options[:autopush])
281+
at = repos[0][1]
282+
if options[:get_setup_env]
283+
_, env = at.agent_prompt_with_env
284+
env.each { |k, v| puts "#{k}=#{v}" }
285+
else
286+
puts at.agent_prompt_with_autopush_setup(autopush: options[:autopush])
287+
end
279288
return
280289
end
281290

282291
dir_messages = []
283-
repos.each do |dir, at|
292+
repos.each do |dir, agent_tasks|
284293
next if dir.nil?
285294

286295
begin
287-
msg = at.agent_prompt_with_autopush_setup(autopush: options[:autopush])
288-
dir_messages << [dir, msg] if msg && !msg.empty?
296+
if options[:get_setup_env]
297+
_, env = agent_tasks.agent_prompt_with_env
298+
dir_messages << [dir, env.map { |k, v| "#{k}=#{v}" }.join("\n")]
299+
else
300+
msg = agent_tasks.agent_prompt_with_autopush_setup(autopush: options[:autopush])
301+
dir_messages << [dir, msg] if msg && !msg.empty?
302+
end
289303
rescue StandardError
290304
next
291305
end
@@ -295,10 +309,8 @@ def run_get_task(args = [])
295309
puts "Error: Could not find repository root from #{Dir.pwd}"
296310
exit 1
297311
elsif dir_messages.length == 1
298-
# Single repo case: display without directory hints
299312
puts dir_messages[0][1]
300313
else
301-
# Multiple repos case: display with directory hints
302314
output = dir_messages.map { |dir, msg| "In directory `#{dir}`:\n#{msg}" }.join("\n\n")
303315
puts output
304316
end

0 commit comments

Comments
 (0)