@guildai/cli 0.4.0 → 0.5.0
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 +8 -3
- package/dist/commands/agent/clone.js +6 -3
- package/dist/commands/agent/init.js +9 -5
- package/dist/commands/agent/save.js +53 -35
- package/dist/lib/git.d.ts +9 -0
- package/dist/lib/git.js +24 -1
- package/docs/CLI_WORKFLOW.md +18 -9
- package/docs/getting-started.md +21 -14
- package/docs/skills/agent-dev.md +19 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,8 +28,12 @@ guild agent init --name my-agent
|
|
|
28
28
|
### 3. Develop and Save
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
# Edit agent.ts, then save
|
|
32
|
-
|
|
31
|
+
# Edit agent.ts, then commit and save
|
|
32
|
+
git add . && git commit -m "Initial implementation"
|
|
33
|
+
guild agent save
|
|
34
|
+
|
|
35
|
+
# Or stage+commit+push in one step
|
|
36
|
+
guild agent save -A --message "Initial implementation"
|
|
33
37
|
```
|
|
34
38
|
|
|
35
39
|
### 4. Test Your Agent
|
|
@@ -54,7 +58,8 @@ guild auth status # Check authentication status
|
|
|
54
58
|
|
|
55
59
|
```bash
|
|
56
60
|
guild agent init --name my-agent # Initialize a new agent
|
|
57
|
-
guild agent save
|
|
61
|
+
guild agent save # Push commits and create a version
|
|
62
|
+
guild agent save -A --message "..." # Stage+commit+push in one step
|
|
58
63
|
guild agent versions # List versions
|
|
59
64
|
guild agent publish # Publish latest draft version
|
|
60
65
|
guild agent unpublish # Unpublish latest published version
|
|
@@ -5,7 +5,7 @@ import { handleAxiosError, ErrorCodes } from '../../lib/errors.js';
|
|
|
5
5
|
import * as fs from 'fs/promises';
|
|
6
6
|
import * as path from 'path';
|
|
7
7
|
import { getAuthenticatedUrl } from '../../lib/auth.js';
|
|
8
|
-
import { runGit, GitError, formatGitError } from '../../lib/git.js';
|
|
8
|
+
import { runGit, GitError, formatGitError, installPrePushHook } from '../../lib/git.js';
|
|
9
9
|
import { createOutputWriter } from '../../lib/output.js';
|
|
10
10
|
async function isDirectoryEmpty(dirPath) {
|
|
11
11
|
try {
|
|
@@ -57,6 +57,8 @@ export function createAgentCloneCommand() {
|
|
|
57
57
|
}
|
|
58
58
|
await runGit(['clone', cloneUrl, targetDir]);
|
|
59
59
|
output.progress(`✓ Cloned repository to ${targetDir}`);
|
|
60
|
+
await installPrePushHook(targetDir);
|
|
61
|
+
output.progress('✓ Installed pre-push hook');
|
|
60
62
|
// Create guild.json if it doesn't exist
|
|
61
63
|
const guildJsonPath = path.join(targetDir, 'guild.json');
|
|
62
64
|
const guildJsonExists = await fs
|
|
@@ -80,8 +82,9 @@ export function createAgentCloneCommand() {
|
|
|
80
82
|
output.progress('Next steps:');
|
|
81
83
|
output.progress(` 1. cd ${targetDir}`);
|
|
82
84
|
output.progress(' 2. Make your changes to the code');
|
|
83
|
-
output.progress(
|
|
84
|
-
output.progress(
|
|
85
|
+
output.progress(' 3. git add . && git commit -m "your changes"');
|
|
86
|
+
output.progress(" 4. Run 'guild agent save' to push and create a version");
|
|
87
|
+
output.progress(` 5. Run 'guild agent test' to test your changes`);
|
|
85
88
|
}
|
|
86
89
|
catch (error) {
|
|
87
90
|
if (error instanceof GitError) {
|
|
@@ -8,7 +8,7 @@ import * as fs from 'fs/promises';
|
|
|
8
8
|
import * as path from 'path';
|
|
9
9
|
import * as readline from 'readline';
|
|
10
10
|
import { getAuthenticatedUrl } from '../../lib/auth.js';
|
|
11
|
-
import { runGit, GitError, formatGitError } from '../../lib/git.js';
|
|
11
|
+
import { runGit, GitError, formatGitError, installPrePushHook } from '../../lib/git.js';
|
|
12
12
|
import { resolveOwnerId } from '../../lib/owner-helpers.js';
|
|
13
13
|
const TEMPLATE_CHOICES = [
|
|
14
14
|
{
|
|
@@ -311,6 +311,8 @@ export function createAgentInitCommand() {
|
|
|
311
311
|
// .gitignore doesn't exist (backend should have created it), create it
|
|
312
312
|
await fs.writeFile(gitignorePath, 'guild.json\n');
|
|
313
313
|
}
|
|
314
|
+
// Install pre-push hook to block direct git push
|
|
315
|
+
await installPrePushHook(targetDir);
|
|
314
316
|
// Complete progress tracking
|
|
315
317
|
steps.complete('Agent initialized successfully');
|
|
316
318
|
// Display next steps
|
|
@@ -318,13 +320,15 @@ export function createAgentInitCommand() {
|
|
|
318
320
|
if (options.directory) {
|
|
319
321
|
format.detail(`1. cd ${targetDir}`);
|
|
320
322
|
format.detail('2. Edit agent.ts to implement your agent logic');
|
|
321
|
-
format.detail(
|
|
322
|
-
format.detail(
|
|
323
|
+
format.detail('3. git add . && git commit -m "Initial implementation"');
|
|
324
|
+
format.detail("4. Run 'guild agent save' to push and create a version");
|
|
325
|
+
format.detail(`5. Run 'guild agent test' to test your agent`);
|
|
323
326
|
}
|
|
324
327
|
else {
|
|
325
328
|
format.detail('1. Edit agent.ts to implement your agent logic');
|
|
326
|
-
format.detail(
|
|
327
|
-
format.detail(
|
|
329
|
+
format.detail('2. git add . && git commit -m "Initial implementation"');
|
|
330
|
+
format.detail("3. Run 'guild agent save' to push and create a version");
|
|
331
|
+
format.detail(`4. Run 'guild agent test' to test your agent`);
|
|
328
332
|
}
|
|
329
333
|
}
|
|
330
334
|
catch (error) {
|
|
@@ -12,8 +12,9 @@ import { pollUntilComplete } from '../../lib/polling.js';
|
|
|
12
12
|
export function createAgentSaveCommand() {
|
|
13
13
|
const cmd = new Command('save');
|
|
14
14
|
cmd
|
|
15
|
-
.description('
|
|
16
|
-
.option('--
|
|
15
|
+
.description('Push committed changes to Guild and create a version')
|
|
16
|
+
.option('-A, --all', 'Stage all changes and commit before pushing', false)
|
|
17
|
+
.option('--message <text>', 'Commit message (required with --all)')
|
|
17
18
|
.option('--wait', 'Wait for validation to complete before returning', false)
|
|
18
19
|
.option('--publish', 'Publish after validation passes (implies --wait)', false)
|
|
19
20
|
.option('--json', 'Output JSON only (no progress messages)', false)
|
|
@@ -21,9 +22,9 @@ export function createAgentSaveCommand() {
|
|
|
21
22
|
const cwd = process.cwd();
|
|
22
23
|
let guildConfig = null;
|
|
23
24
|
const output = createOutputWriter();
|
|
24
|
-
//
|
|
25
|
-
if (!options.message) {
|
|
26
|
-
output.error('Commit message is required', 'Provide a message describing your changes:\n guild agent save --message "Add new feature"');
|
|
25
|
+
// With --all, a commit message is required
|
|
26
|
+
if (options.all && !options.message) {
|
|
27
|
+
output.error('Commit message is required with --all', 'Provide a message describing your changes:\n guild agent save -A --message "Add new feature"');
|
|
27
28
|
process.exit(1);
|
|
28
29
|
}
|
|
29
30
|
try {
|
|
@@ -39,45 +40,60 @@ export function createAgentSaveCommand() {
|
|
|
39
40
|
}
|
|
40
41
|
// Read guild.json
|
|
41
42
|
guildConfig = JSON.parse(await fs.readFile(guildJsonPath, 'utf-8'));
|
|
42
|
-
// Check for uncommitted changes
|
|
43
|
+
// Check for uncommitted changes and unpushed commits
|
|
43
44
|
const { stdout: statusOutput } = await runGit(['status', '--porcelain'], {
|
|
44
45
|
cwd,
|
|
45
46
|
});
|
|
46
47
|
const hasUncommittedChanges = statusOutput.trim().length > 0;
|
|
47
48
|
let hasUnpushedCommits = false;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
// Check for unpushed commits
|
|
50
|
+
try {
|
|
51
|
+
const { stdout: branchForCheck } = await runGit(['rev-parse', '--abbrev-ref', 'HEAD'], { cwd });
|
|
52
|
+
const { stdout: unpushed } = await runGit(['log', `origin/${branchForCheck.trim()}..HEAD`, '--oneline'], { cwd });
|
|
53
|
+
hasUnpushedCommits = unpushed.trim().length > 0;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// No remote tracking branch yet — if HEAD has commits, treat
|
|
57
|
+
// as unpushed so the push flow can create the remote branch.
|
|
51
58
|
try {
|
|
52
|
-
const { stdout:
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
const { stdout: logOutput } = await runGit(['log', '--oneline', '-1'], {
|
|
60
|
+
cwd,
|
|
61
|
+
});
|
|
62
|
+
hasUnpushedCommits = logOutput.trim().length > 0;
|
|
55
63
|
}
|
|
56
64
|
catch {
|
|
57
|
-
|
|
58
|
-
// as unpushed so the push flow can create the remote branch.
|
|
59
|
-
try {
|
|
60
|
-
const { stdout: logOutput } = await runGit(['log', '--oneline', '-1'], {
|
|
61
|
-
cwd,
|
|
62
|
-
});
|
|
63
|
-
hasUnpushedCommits = logOutput.trim().length > 0;
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
hasUnpushedCommits = false;
|
|
67
|
-
}
|
|
65
|
+
hasUnpushedCommits = false;
|
|
68
66
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
}
|
|
68
|
+
if (options.all) {
|
|
69
|
+
// --all: stage and commit before pushing
|
|
70
|
+
if (hasUncommittedChanges) {
|
|
71
|
+
await runGit(['add', '-A'], { cwd });
|
|
72
|
+
output.progress('✓ Staged changes');
|
|
73
|
+
await runGit(['commit', '-m', options.message], { cwd });
|
|
74
|
+
output.progress('✓ Committed locally');
|
|
75
|
+
hasUnpushedCommits = true;
|
|
72
76
|
}
|
|
73
|
-
output.progress('✓ Found unpushed commits, resuming push...');
|
|
74
77
|
}
|
|
75
78
|
else {
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
// Default: push-only, no staging or committing
|
|
80
|
+
if (!hasUnpushedCommits && hasUncommittedChanges) {
|
|
81
|
+
output.error('Uncommitted changes', 'You have uncommitted changes. Either commit them first:\n git add . && git commit -m "your message"\n\nOr use --all to stage and commit automatically:\n guild agent save -A --message "your message"');
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (!hasUnpushedCommits) {
|
|
86
|
+
output.error('No changes to save', 'Working tree is clean and there are no unpushed commits.');
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
// Resolve version summary: use --message if provided, otherwise
|
|
90
|
+
// extract the latest commit message.
|
|
91
|
+
let versionMessage = options.message;
|
|
92
|
+
if (!versionMessage) {
|
|
93
|
+
const { stdout: commitMsg } = await runGit(['log', '-1', '--pretty=%s'], {
|
|
94
|
+
cwd,
|
|
95
|
+
});
|
|
96
|
+
versionMessage = commitMsg.trim();
|
|
81
97
|
}
|
|
82
98
|
// Get remote URL with auth credentials
|
|
83
99
|
const { stdout: remoteUrl } = await runGit(['remote', 'get-url', 'origin'], {
|
|
@@ -94,8 +110,9 @@ export function createAgentSaveCommand() {
|
|
|
94
110
|
});
|
|
95
111
|
const currentBranch = branchName.trim();
|
|
96
112
|
// Pull remote changes first (rebase to avoid merge commits)
|
|
113
|
+
const gitEnv = { GUILD_AGENT_SAVE: '1' };
|
|
97
114
|
try {
|
|
98
|
-
const { stdout: pullOutput } = await runGit(['pull', '--rebase', authenticatedUrl, currentBranch], { cwd });
|
|
115
|
+
const { stdout: pullOutput } = await runGit(['pull', '--rebase', authenticatedUrl, currentBranch], { cwd, env: gitEnv });
|
|
99
116
|
if (pullOutput.includes('Updating') ||
|
|
100
117
|
pullOutput.includes('Fast-forward')) {
|
|
101
118
|
output.progress('✓ Synced with remote');
|
|
@@ -132,6 +149,7 @@ export function createAgentSaveCommand() {
|
|
|
132
149
|
try {
|
|
133
150
|
await runGit(['push', authenticatedUrl, `HEAD:${currentBranch}`], {
|
|
134
151
|
cwd,
|
|
152
|
+
env: gitEnv,
|
|
135
153
|
});
|
|
136
154
|
break;
|
|
137
155
|
}
|
|
@@ -180,7 +198,7 @@ export function createAgentSaveCommand() {
|
|
|
180
198
|
const client = new GuildAPIClient();
|
|
181
199
|
let version = await client.post(`/agents/${guildConfig.agent_id}/versions`, {
|
|
182
200
|
commit_sha: commitSha,
|
|
183
|
-
summary:
|
|
201
|
+
summary: versionMessage,
|
|
184
202
|
version_type: 'COMMITTED',
|
|
185
203
|
});
|
|
186
204
|
output.progress(`✓ Created version (${version.id})`);
|
|
@@ -226,7 +244,7 @@ export function createAgentSaveCommand() {
|
|
|
226
244
|
failureDetails = 'Could not fetch validation details.';
|
|
227
245
|
}
|
|
228
246
|
failureDetails +=
|
|
229
|
-
'\n\nFix the issues,
|
|
247
|
+
'\n\nFix the issues, commit, and save a new version:\n git add . && git commit -m "Fix validation errors"\n guild agent save';
|
|
230
248
|
output.error('Validation failed', failureDetails);
|
|
231
249
|
process.exit(1);
|
|
232
250
|
}
|
package/dist/lib/git.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export interface GitOptions {
|
|
|
6
6
|
cwd?: string;
|
|
7
7
|
/** Timeout in milliseconds (default: 30000 for most commands) */
|
|
8
8
|
timeout?: number;
|
|
9
|
+
/** Extra environment variables to pass to the git subprocess */
|
|
10
|
+
env?: Record<string, string>;
|
|
9
11
|
}
|
|
10
12
|
/**
|
|
11
13
|
* Result from a git command
|
|
@@ -57,4 +59,11 @@ export declare function runGit(args: string[], options?: GitOptions): Promise<Gi
|
|
|
57
59
|
* Returns a user-friendly error message with the git output.
|
|
58
60
|
*/
|
|
59
61
|
export declare function formatGitError(error: GitError): string;
|
|
62
|
+
/**
|
|
63
|
+
* Install a pre-push hook that blocks direct git push.
|
|
64
|
+
*
|
|
65
|
+
* The hook allows pushes only when the GUILD_AGENT_SAVE env var is set,
|
|
66
|
+
* which guild agent save sets automatically.
|
|
67
|
+
*/
|
|
68
|
+
export declare function installPrePushHook(targetDir: string): Promise<void>;
|
|
60
69
|
//# sourceMappingURL=git.d.ts.map
|
package/dist/lib/git.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* by preventing interactive prompts and providing clear error messages.
|
|
7
7
|
*/
|
|
8
8
|
import { execa } from 'execa';
|
|
9
|
+
import * as fs from 'fs/promises';
|
|
10
|
+
import * as path from 'path';
|
|
9
11
|
import { debug } from './errors.js';
|
|
10
12
|
/**
|
|
11
13
|
* Error thrown when a git command fails
|
|
@@ -71,7 +73,7 @@ const NETWORK_COMMANDS = ['clone', 'push', 'pull', 'fetch'];
|
|
|
71
73
|
* }
|
|
72
74
|
*/
|
|
73
75
|
export async function runGit(args, options = {}) {
|
|
74
|
-
const { cwd, timeout: customTimeout } = options;
|
|
76
|
+
const { cwd, timeout: customTimeout, env: extraEnv } = options;
|
|
75
77
|
// Determine timeout based on command type
|
|
76
78
|
const isNetworkCommand = args.length > 0 && NETWORK_COMMANDS.includes(args[0]);
|
|
77
79
|
const timeout = customTimeout ?? (isNetworkCommand ? NETWORK_TIMEOUT : DEFAULT_TIMEOUT);
|
|
@@ -88,6 +90,7 @@ export async function runGit(args, options = {}) {
|
|
|
88
90
|
GIT_TERMINAL_PROMPT: '0',
|
|
89
91
|
// Prevent SSH from prompting for passwords/passphrases
|
|
90
92
|
GIT_SSH_COMMAND: 'ssh -o BatchMode=yes',
|
|
93
|
+
...extraEnv,
|
|
91
94
|
},
|
|
92
95
|
});
|
|
93
96
|
}
|
|
@@ -149,4 +152,24 @@ export function formatGitError(error) {
|
|
|
149
152
|
}
|
|
150
153
|
return lines.join('\n');
|
|
151
154
|
}
|
|
155
|
+
const PRE_PUSH_HOOK = `#!/bin/sh
|
|
156
|
+
if [ "$GUILD_AGENT_SAVE" != "1" ]; then
|
|
157
|
+
echo "Please use \\\`guild agent save\\\` to push."
|
|
158
|
+
exit 1
|
|
159
|
+
fi
|
|
160
|
+
exit 0
|
|
161
|
+
`;
|
|
162
|
+
/**
|
|
163
|
+
* Install a pre-push hook that blocks direct git push.
|
|
164
|
+
*
|
|
165
|
+
* The hook allows pushes only when the GUILD_AGENT_SAVE env var is set,
|
|
166
|
+
* which guild agent save sets automatically.
|
|
167
|
+
*/
|
|
168
|
+
export async function installPrePushHook(targetDir) {
|
|
169
|
+
const hooksDir = path.join(targetDir, '.git', 'hooks');
|
|
170
|
+
await fs.mkdir(hooksDir, { recursive: true });
|
|
171
|
+
await fs.writeFile(path.join(hooksDir, 'pre-push'), PRE_PUSH_HOOK, {
|
|
172
|
+
mode: 0o755,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
152
175
|
//# sourceMappingURL=git.js.map
|
package/docs/CLI_WORKFLOW.md
CHANGED
|
@@ -19,8 +19,12 @@ guild agent create my-agent --template LLM
|
|
|
19
19
|
guild agent clone guildai/dev-assistant
|
|
20
20
|
cd dev-assistant
|
|
21
21
|
|
|
22
|
-
# Save changes (commits
|
|
23
|
-
|
|
22
|
+
# Save changes (pushes commits to Guild server)
|
|
23
|
+
git add . && git commit -m "Description of changes"
|
|
24
|
+
guild agent save
|
|
25
|
+
|
|
26
|
+
# Or stage+commit+push in one step
|
|
27
|
+
guild agent save -A --message "Description of changes"
|
|
24
28
|
|
|
25
29
|
# Save and publish
|
|
26
30
|
guild agent save --message "Description" --wait --publish
|
|
@@ -37,9 +41,8 @@ guild agent save --message "Description" --wait --publish
|
|
|
37
41
|
## NEVER Do These Things
|
|
38
42
|
|
|
39
43
|
- ❌ Manually create `package.json`, `tsconfig.json`, or `guild.json`
|
|
40
|
-
- ❌ Run `git push` directly (use `guild agent save`)
|
|
44
|
+
- ❌ Run `git push` directly (use `guild agent save` — a pre-push hook blocks direct pushes)
|
|
41
45
|
- ❌ Run `git pull` directly (use `guild agent pull`)
|
|
42
|
-
- ❌ Run `git commit` directly (use `guild agent save`)
|
|
43
46
|
- ❌ Edit `guild.json` (it's generated and gitignored)
|
|
44
47
|
|
|
45
48
|
## Common Commands
|
|
@@ -93,15 +96,21 @@ guild agent grep "pattern" --published
|
|
|
93
96
|
|
|
94
97
|
### Saving Changes
|
|
95
98
|
|
|
99
|
+
Git owns the working tree, Guild owns the remote. Use normal git commands to stage and commit, then `guild agent save` to push and create a version.
|
|
100
|
+
|
|
96
101
|
```bash
|
|
97
|
-
#
|
|
98
|
-
|
|
102
|
+
# Commit with git, then push via Guild (creates draft)
|
|
103
|
+
git add . && git commit -m "WIP: still testing"
|
|
104
|
+
guild agent save
|
|
105
|
+
|
|
106
|
+
# Or stage+commit+push in one step
|
|
107
|
+
guild agent save -A --message "WIP: still testing"
|
|
99
108
|
|
|
100
109
|
# Save and wait for validation
|
|
101
110
|
guild agent save --message "Fix bug" --wait
|
|
102
111
|
|
|
103
112
|
# Save, validate, and publish
|
|
104
|
-
guild agent save --message "Release v1.0" --wait --publish
|
|
113
|
+
guild agent save -A --message "Release v1.0" --wait --publish
|
|
105
114
|
```
|
|
106
115
|
|
|
107
116
|
### Publishing
|
|
@@ -150,9 +159,9 @@ my-agent/
|
|
|
150
159
|
|
|
151
160
|
## Troubleshooting
|
|
152
161
|
|
|
153
|
-
### "No changes to
|
|
162
|
+
### "No changes to save"
|
|
154
163
|
|
|
155
|
-
|
|
164
|
+
Working tree is clean and there are no unpushed commits. Make a code change, commit it, then run `guild agent save` again.
|
|
156
165
|
|
|
157
166
|
### "guild.json not found"
|
|
158
167
|
|
package/docs/getting-started.md
CHANGED
|
@@ -103,9 +103,10 @@ Press `Ctrl+C` to exit.
|
|
|
103
103
|
### 4. Save and publish
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
|
-
guild agent save --message "First version" --wait --publish
|
|
106
|
+
guild agent save -A --message "First version" --wait --publish
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
- `-A` stages and commits all changes before pushing
|
|
109
110
|
- `--wait` blocks until validation passes
|
|
110
111
|
- `--publish` makes the agent available in the Guild catalog
|
|
111
112
|
|
|
@@ -288,16 +289,25 @@ guild agent chat "Hello" # Send a single message
|
|
|
288
289
|
|
|
289
290
|
### 3. Save your work
|
|
290
291
|
|
|
292
|
+
Commit with git, then push via Guild:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
git add . && git commit -m "Add Slack notifications"
|
|
296
|
+
guild agent save
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Or stage+commit+push in one step:
|
|
300
|
+
|
|
291
301
|
```bash
|
|
292
|
-
guild agent save --message "Add Slack notifications"
|
|
302
|
+
guild agent save -A --message "Add Slack notifications"
|
|
293
303
|
```
|
|
294
304
|
|
|
295
|
-
This
|
|
305
|
+
This pushes your commits and creates a new version in the Guild backend. Versions start as drafts.
|
|
296
306
|
|
|
297
307
|
### 4. Publish
|
|
298
308
|
|
|
299
309
|
```bash
|
|
300
|
-
guild agent save --message "Ready to ship" --wait --publish
|
|
310
|
+
guild agent save -A --message "Ready to ship" --wait --publish
|
|
301
311
|
```
|
|
302
312
|
|
|
303
313
|
`--wait` blocks until validation passes. `--publish` makes the agent available in the catalog. You can also publish separately:
|
|
@@ -319,7 +329,7 @@ guild agent code # View source of latest version
|
|
|
319
329
|
- Agent code lives in `agent.ts` (typically at the project root, but can be in a subdirectory like `src/`).
|
|
320
330
|
- Don't add `@guildai/agents-sdk`, `zod`, or `@guildai-services/*` to `package.json`. The runtime provides them. Only add third-party packages you actually use.
|
|
321
331
|
- Always call tools through `task.tools.<name>(args)`. Never access services directly.
|
|
322
|
-
-
|
|
332
|
+
- Use `git add` and `git commit` to manage your working tree. Use `guild agent save` to push and create versions. Don't use `git push` directly (a pre-push hook blocks it).
|
|
323
333
|
- Don't edit `guild.json` — it's managed by the CLI.
|
|
324
334
|
|
|
325
335
|
## Other Commands
|
|
@@ -396,13 +406,9 @@ guild agent get
|
|
|
396
406
|
guild agent get <agent-id>
|
|
397
407
|
```
|
|
398
408
|
|
|
399
|
-
### "No changes to
|
|
400
|
-
|
|
401
|
-
If a previous `guild agent save` committed locally but failed to push (e.g., network error), just run save again. It detects the unpushed commits and resumes:
|
|
409
|
+
### "No changes to save"
|
|
402
410
|
|
|
403
|
-
|
|
404
|
-
guild agent save --message "Retry"
|
|
405
|
-
```
|
|
411
|
+
Working tree is clean and there are no unpushed commits. Make a code change, commit it, then run `guild agent save` again. If a previous save committed locally but failed to push (e.g., network error), just run `guild agent save` again — it detects the unpushed commits and resumes.
|
|
406
412
|
|
|
407
413
|
### Validation failures
|
|
408
414
|
|
|
@@ -412,8 +418,9 @@ After saving, if validation fails:
|
|
|
412
418
|
# Check the latest version for errors
|
|
413
419
|
guild agent versions --limit 1
|
|
414
420
|
|
|
415
|
-
# Fix the issue and save again
|
|
416
|
-
|
|
421
|
+
# Fix the issue, commit, and save again
|
|
422
|
+
git add . && git commit -m "Fix validation error"
|
|
423
|
+
guild agent save --wait
|
|
417
424
|
```
|
|
418
425
|
|
|
419
426
|
### Agent test not responding
|
|
@@ -421,7 +428,7 @@ guild agent save --message "Fix validation error" --wait
|
|
|
421
428
|
If `guild agent test` hangs or produces no output:
|
|
422
429
|
|
|
423
430
|
1. Check your agent code compiles: look for TypeScript errors in `agent.ts`
|
|
424
|
-
2. Make sure you've saved at least once: `guild agent save --message "initial"`
|
|
431
|
+
2. Make sure you've saved at least once: `guild agent save -A --message "initial"`
|
|
425
432
|
3. Try a single message instead: `guild agent chat "hello"`
|
|
426
433
|
|
|
427
434
|
## Next Steps
|
package/docs/skills/agent-dev.md
CHANGED
|
@@ -53,18 +53,24 @@ guild agent clone owner/agent-name
|
|
|
53
53
|
|
|
54
54
|
### Syncing and Saving
|
|
55
55
|
|
|
56
|
+
Git owns the working tree, Guild owns the remote. Use normal git commands to stage and commit, then `guild agent save` to push and create a version.
|
|
57
|
+
|
|
56
58
|
```bash
|
|
57
59
|
# Pull remote changes (e.g., edits from other collaborators)
|
|
58
60
|
guild agent pull
|
|
59
61
|
|
|
60
|
-
#
|
|
61
|
-
|
|
62
|
+
# Commit with git, then push via Guild (creates draft)
|
|
63
|
+
git add . && git commit -m "Description of changes"
|
|
64
|
+
guild agent save
|
|
65
|
+
|
|
66
|
+
# Or stage+commit+push in one step
|
|
67
|
+
guild agent save -A --message "Description of changes"
|
|
62
68
|
|
|
63
69
|
# Save and wait for validation
|
|
64
70
|
guild agent save --message "Fix bug" --wait
|
|
65
71
|
|
|
66
72
|
# Save, validate, and publish
|
|
67
|
-
guild agent save --message "Release v1.0" --wait --publish
|
|
73
|
+
guild agent save -A --message "Release v1.0" --wait --publish
|
|
68
74
|
```
|
|
69
75
|
|
|
70
76
|
### Testing
|
|
@@ -87,10 +93,13 @@ guild agent chat "Hello, can you help me?"
|
|
|
87
93
|
### For Creating and Modifying
|
|
88
94
|
|
|
89
95
|
- ✅ `guild agent create`, `guild agent init`, `guild agent clone`
|
|
90
|
-
- ✅ `
|
|
96
|
+
- ✅ `git add`, `git commit` (manage your own working tree)
|
|
97
|
+
- ✅ `guild agent save` (push commits and create a version)
|
|
98
|
+
- ✅ `guild agent save -A --message "desc"` (stage+commit+push in one step)
|
|
91
99
|
- ✅ `guild agent pull` (sync remote changes into local directory)
|
|
92
100
|
- ✅ `guild agent test`, `guild agent chat`
|
|
93
|
-
- ❌ NEVER use `git
|
|
101
|
+
- ❌ NEVER use `git push` directly (a pre-push hook blocks this — use `guild agent save`)
|
|
102
|
+
- ❌ NEVER use `gh repo` for agent operations
|
|
94
103
|
- ❌ NEVER manually create `package.json`, `tsconfig.json`, or `guild.json`
|
|
95
104
|
|
|
96
105
|
### For Investigating and Debugging
|
|
@@ -702,7 +711,8 @@ guild agent create <name> --template LLM # Create with specific templa
|
|
|
702
711
|
guild agent init # Initialize local workspace
|
|
703
712
|
guild agent init --fork <agent-id> # Fork existing agent
|
|
704
713
|
guild agent pull # Pull remote changes
|
|
705
|
-
guild agent save
|
|
714
|
+
guild agent save # Push commits and create a draft version
|
|
715
|
+
guild agent save -A --message "description" # Stage+commit+push in one step
|
|
706
716
|
guild agent save --message "v1.0" --wait --publish # Save + validate + publish
|
|
707
717
|
guild agent test # Interactive test
|
|
708
718
|
guild agent test --ephemeral # Ephemeral test
|
|
@@ -731,9 +741,9 @@ GUILD_OWNER_ID=<id> guild agent init --name my-agent # Override owner for agent
|
|
|
731
741
|
|
|
732
742
|
## Troubleshooting
|
|
733
743
|
|
|
734
|
-
### "No changes to
|
|
744
|
+
### "No changes to save"
|
|
735
745
|
|
|
736
|
-
|
|
746
|
+
Working tree is clean and there are no unpushed commits. Make a code change, commit it, then run `guild agent save` again.
|
|
737
747
|
|
|
738
748
|
### "guild.json not found"
|
|
739
749
|
|
|
@@ -757,5 +767,5 @@ If `guild.json` is tracked in git (it shouldn't be):
|
|
|
757
767
|
```bash
|
|
758
768
|
echo "guild.json" >> .gitignore
|
|
759
769
|
git rm --cached guild.json
|
|
760
|
-
guild agent save --message "fix: Add guild.json to gitignore"
|
|
770
|
+
guild agent save -A --message "fix: Add guild.json to gitignore"
|
|
761
771
|
```
|