Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/src/content/docs/docs/reference/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ With `--json`, each entry in the `plugins` array includes a `kind` field (`"plug

```bash
allagents workspace init <path> [--from <source>]
allagents workspace setup
allagents workspace status # alias for `allagents status`
allagents workspace plugin install <plugin@marketplace> [--scope <scope>]
allagents workspace plugin remove <plugin> [--scope <scope>]
Expand All @@ -82,6 +83,34 @@ Initialize a new workspace from a template:

When using a GitHub source, AllAgents fetches `workspace.yaml` from `.allagents/workspace.yaml` or `workspace.yaml` in the target path.

### workspace setup

Run setup entries from `.allagents/workspace.yaml` that match the current
platform and architecture:

```bash
allagents workspace setup
```

This explicit action is the only path that executes setup commands. `workspace
init`, `update`, and `workspace sync` never run them because workspace templates
may come from untrusted remote sources. Review every command before running
setup.

String entries run everywhere. Object entries may restrict execution with
`platforms` using Node platform names such as `linux`, `darwin`, and `win32`,
and with `architectures` using names such as `x64` and `arm64`. When both are
present, both must match. Nonmatching commands are reported as skipped.

Matching commands are shown immediately before they run, execute sequentially
from the workspace root with inherited terminal I/O, and stop on the first
nonzero exit or terminating signal.

With `--json`, stdout contains one deterministic result document preserving
declaration order. Each entry reports `succeeded`, `failed`, or `skipped`, its
nullable exit code and signal, and a skip reason when applicable. Command
announcements and command output are forwarded to stderr.

### workspace plugin install / remove

| Flag | Description |
Expand Down
39 changes: 39 additions & 0 deletions docs/src/content/docs/docs/reference/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ description: Configuration file reference.
The workspace configuration file defines repositories, plugins, workspace file sync, and target clients.

```yaml
setup:
- bun install
- bun run build

# Workspace file sync (optional)
workspace:
source: ../shared-config # Default base for relative file paths
Expand Down Expand Up @@ -49,6 +53,41 @@ clients:
- cursor
```

### Setup Commands

The optional top-level `setup` field is an ordered list. A string runs on every
platform. Use an object to select operating systems or CPU architectures:

```yaml
setup:
- bun install
- run: curl -fsSL https://example.com/install.sh | sh
platforms: [linux, darwin]
architectures: [x64, arm64]
- run: 'powershell -ExecutionPolicy Bypass -c "irm https://example.com/install.ps1 | iex"'
platforms: [win32]
```

| Field | Required | Description |
|-------|----------|-------------|
| `run` | Yes for object entries | Shell command to execute |
| `platforms` | No | Allowed Node platform names, such as `linux`, `darwin`, or `win32` |
| `architectures` | No | Allowed Node architecture names, such as `x64` or `arm64` |

When both selectors are present, the current platform and architecture must
match. Nonmatching entries are reported as skipped without executing.

Run setup only with the explicit `allagents workspace setup` action. AllAgents
never runs it during `init`, `update`, or `sync`. This is a trust boundary:
remote workspace templates are untrusted until you review their setup commands
and explicitly choose to execute them.

AllAgents reports entries in declaration order. Matching commands are shown
immediately before they run, execute sequentially from the workspace root,
inherit terminal I/O, and stop after the first nonzero exit or terminating
signal. In `--json` mode, command announcements and output are forwarded to
stderr so stdout remains one deterministic JSON document.

### Plugin Skills

Control which skills are synced per plugin using the inline `skills` field on plugin entries:
Expand Down
10 changes: 10 additions & 0 deletions examples/workspaces/engineering/.allagents/workspace.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
version: 2

setup:
- run: curl -fsSL https://herdr.dev/install.sh | sh
platforms: [linux, darwin]
- run: 'powershell -ExecutionPolicy Bypass -c "irm https://herdr.dev/install.ps1 | iex"'
platforms: [win32]

repositories: []

plugins:
Expand Down Expand Up @@ -27,5 +33,9 @@ plugins:
skills:
- research/llm-wiki

- source: https://github.com/herdrdev/herdr
skills:
- herdr

clients:
- universal
28 changes: 17 additions & 11 deletions src/cli/agent-help.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
import type { AgentCommandMeta } from './help.js';
import { normalizeSkillHelpArgs } from './skill-arg-normalizer.js';

import { initMeta, syncMeta, statusMeta } from './metadata/workspace.js';
import {
marketplaceListMeta,
skillsAddMeta,
skillsListMeta,
skillsRemoveMeta,
skillsSearchMeta,
skillsUpdateMeta,
} from './metadata/plugin-skills.js';
import {
marketplaceAddMeta,
marketplaceBrowseMeta,
marketplaceListMeta,
marketplaceRemoveMeta,
marketplaceUpdateMeta,
marketplaceBrowseMeta,
pluginListMeta,
pluginValidateMeta,
pluginInstallMeta,
pluginListMeta,
pluginUninstallMeta,
pluginValidateMeta,
} from './metadata/plugin.js';
import { updateMeta } from './metadata/self.js';
import {
skillsListMeta,
skillsAddMeta,
skillsRemoveMeta,
skillsSearchMeta,
skillsUpdateMeta,
} from './metadata/plugin-skills.js';
initMeta,
setupMeta,
statusMeta,
syncMeta,
} from './metadata/workspace.js';

const allCommands: AgentCommandMeta[] = [
initMeta,
setupMeta,
syncMeta,
statusMeta,
pluginInstallMeta,
Expand Down
74 changes: 74 additions & 0 deletions src/cli/commands/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
removeRepository,
updateAgentFiles,
} from '../../core/workspace-repo.js';
import { runWorkspaceSetup } from '../../core/workspace-setup.js';
import { initWorkspace } from '../../core/workspace.js';
import {
type ClientEntry,
Expand Down Expand Up @@ -48,6 +49,7 @@ import {
import {
initMeta,
pruneMeta,
setupMeta,
statusMeta,
syncMeta,
} from '../metadata/workspace.js';
Expand Down Expand Up @@ -194,6 +196,77 @@ const initCmd = command({
},
});

// =============================================================================
// workspace setup
// =============================================================================

const setupCmd = command({
name: 'setup',
description: buildDescription(setupMeta),
args: {},
handler: async () => {
try {
const result = await runWorkspaceSetup(process.cwd(), {
jsonMode: isJsonMode(),
});
const failed = result.commands.find(({ status }) => status === 'failed');

if (failed) {
const error =
failed.signal !== null
? `Setup command terminated by signal ${failed.signal}: ${failed.command}`
: `Setup command failed with exit code ${failed.exitCode}: ${failed.command}`;
if (isJsonMode()) {
jsonOutput({
success: false,
command: 'workspace setup',
data: result,
error,
});
} else {
console.error(`Error: ${error}`);
}
process.exit(1);
}

if (isJsonMode()) {
jsonOutput({
success: true,
command: 'workspace setup',
data: result,
});
return;
}

if (result.commands.length === 0) {
console.log('No setup commands configured.');
} else {
const ran = result.commands.filter(
({ status }) => status !== 'skipped',
).length;
const skipped = result.commands.length - ran;
console.log(
`Setup complete. ${ran} command(s) ran; ${skipped} skipped.`,
);
}
} catch (error) {
if (error instanceof Error) {
if (isJsonMode()) {
jsonOutput({
success: false,
command: 'workspace setup',
error: error.message,
});
} else {
console.error(`Error: ${error.message}`);
}
process.exit(1);
}
throw error;
}
},
});

// =============================================================================
// workspace sync
// =============================================================================
Expand Down Expand Up @@ -846,6 +919,7 @@ export const workspaceCmd = conciseSubcommands({
'Manage AI agent workspaces - initialize, sync, and configure plugins',
cmds: {
init: initCmd,
setup: setupCmd,
sync: syncCmd,
status: statusCmd,
prune: pruneCmd,
Expand Down
Loading