Skip to content
Open
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
.semgrep @aws-samples/coding-agents-admin
.threat-composer @aws-samples/coding-agents-admin
AGENTS.md @aws-samples/coding-agents-admin
**/AGENTS.md @aws-samples/coding-agents-admin
CLAUDE.md @aws-samples/coding-agents-admin
CODE_OF_CONDUCT.md @aws-samples/coding-agents-admin
contracts @aws-samples/coding-agents-admin
Expand Down
207 changes: 80 additions & 127 deletions AGENTS.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Describe what you intend to contribute. This avoids duplicate work and gives mai

Follow the [Quick Start](./docs/guides/QUICK_START.mdx) to clone, install, and build the project. See the [Developer guide](./docs/guides/DEVELOPER_GUIDE.md) for local testing and the development workflow.

Use **[AGENTS.md](./AGENTS.md)** to understand where to make changes (CDK vs CLI vs agent vs docs), which tests to extend, and common pitfalls (generated docs, mirrored API types, `mise` tasks).
Use **[AGENTS.md](./AGENTS.md)** to understand where to make changes (CDK vs CLI vs agent vs docs), which tests to extend, and common pitfalls (generated docs, mirrored API types, `mise` tasks). Package-specific detail lives in **`AGENTS.md`** under `cdk/`, `cli/`, `agent/`, and `docs/`.

### 3. Implement your change

Expand Down
91 changes: 91 additions & 0 deletions agent/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Agent runtime — agent context

Parent guide: [../AGENTS.md](../AGENTS.md)

You maintain the **Python agent runtime** bundled into the CDK-deployed image: pipeline, runner, hooks, prompts, policy, and progress events.

## Commands (run these)

```bash
mise //agent:quality # lint, type-check, pytest
mise //agent:security # agent-scoped security checks
cd agent && uv run pytest -v # verbose single run
cd agent && uv run pytest tests/test_progress_writer.py -v
```

Root `mise run build` includes `//agent:quality` in parallel with `//cdk:build`.

## Testing

- **Full quality gate:** `mise //agent:quality`
- **Verbose pytest:** `cd agent && uv run pytest -v`
- **Single file:** `cd agent && uv run pytest tests/test_hooks.py -k test_name`
- **With coverage:** see `agent/mise.toml` / `pyproject.toml` for project defaults

| Code | Test location |
|------|---------------|
| `progress_writer.py` | `agent/tests/test_progress_writer.py` |
| `hooks.py`, `policy.py` | `agent/tests/test_hooks.py`, `test_policy.py` |
| `pipeline.py`, `runner.py` | `agent/tests/test_pipeline.py`, etc. |

Use `@pytest.fixture(autouse=True)` to reset shared module state between tests when handlers use circuit breakers or caches.

## Primary locations

| Path | Access | Purpose |
|------|--------|---------|
| `agent/src/pipeline.py`, `runner.py` | WRITE | Task execution loop |
| `agent/src/config.py`, `hooks.py`, `policy.py` | WRITE | Runtime config and gates |
| `agent/src/prompts/` | WRITE | System prompts per workflow |
| `agent/src/progress_writer.py` | WRITE | TaskEvents emission |
| `agent/tests/` | WRITE | pytest suite |
| `agent/README.md` | WRITE | Env vars, PAT notes |
| `cli/src/commands/watch.ts` | WRITE (if event schema changes) | Event consumer |

## Code style

**Progress events** — use `_ProgressWriter`; do not write DynamoDB directly from random call sites:

```python
# ✅ Good — typed writer method (table from TASK_EVENTS_TABLE_NAME env)
from progress_writer import _ProgressWriter

writer = _ProgressWriter(task_id=task_id)
writer.write_agent_milestone("clone_complete", "Repository cloned")

# ❌ Bad — raw boto3, no circuit breaker, ad-hoc shape
dynamodb.put_item(TableName=table, Item={"event_type": {"S": "done"}})
```

**Tests** — pytest classes, explicit fixtures for shared state:

```python
# ✅ Good
@pytest.fixture(autouse=True)
def _reset_shared_circuit_breaker_state():
_reset_circuit_breakers()
yield
_reset_circuit_breakers()

class TestGenerateUlid:
def test_length_is_26(self):
assert len(_generate_ulid()) == 26

# ❌ Bad — no isolation, test order dependency
def test_a():
_ProgressWriter._circuit_open = True # poisons test_b
```

**Silent failures** — do not `except: pass` or return empty defaults without justification; semgrep `AI004` blocks masking (use `nosemgrep` with reason if intentional).

## Boundaries

- ✅ **Always:** Add tests under `agent/tests/` for behavior changes; update `agent/README.md` for new env vars; emit structured progress events for operator-visible milestones
- ⚠️ **Ask first:** Changes to agent–orchestrator contract, Dockerfile base image, new system dependencies in `pyproject.toml`
- 🚫 **Never:** Bump `cedarpy` without bumping `@cedar-policy/cedar-wasm` and refreshing `contracts/cedar-parity/` fixtures; edit only `agent/` and skip `mise //agent:quality` before PR

## Common mistakes

- **Cedar parity** — `cedarpy==4.8.4` (agent) and `@cedar-policy/cedar-wasm` 4.8.2 (cdk) must move together. See [cdk/AGENTS.md](../cdk/AGENTS.md) and `docs/design/CEDAR_HITL_GATES.md` §15.6.
- **Forgotten consumer** — Progress event schema changes need `cli/src/commands/watch.ts` and `test_progress_writer.py` updates.
- **Image bundle** — CDK deploys this tree; root `mise run build` always runs agent quality.
96 changes: 96 additions & 0 deletions cdk/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# CDK package — agent context

Parent guide: [../AGENTS.md](../AGENTS.md)

You are an **ABCA platform engineer** for the `@abca/cdk` package: Lambda handlers, orchestration, CDK stacks/constructs, IAM, and shared API types.

## Commands (run these)

```bash
mise //cdk:compile # TypeScript compile
mise //cdk:test # Jest unit tests
mise //cdk:synth # synth to cdk/cdk.out/
mise //cdk:eslint # ESLint --fix (run after merging main)
mise //cdk:deploy # deploy stack (requires AWS creds)
mise //cdk:diff # diff vs deployed
mise //cdk:destroy # destroy stack
```

## Testing

- **Full suite:** `mise //cdk:test`
- **Single file:** `cd cdk && npx jest test/handlers/shared/validation.test.ts`
- **Pattern:** `cd cdk && npx jest --testPathPattern=orchestrate-task`

**Extend tests when you change:**

| Code | Test location |
|------|---------------|
| Shared handler logic | `cdk/test/handlers/shared/*.test.ts` |
| Handler entrypoints | `cdk/test/handlers/orchestrate-task.test.ts`, `create-task.test.ts`, `webhook-create-task.test.ts` |
| Constructs | `cdk/test/constructs/task-orchestrator.test.ts`, `task-api.test.ts` |

Construct tests: synthesize each distinct stack config once in `beforeAll`, assert against cached `Template` — do not re-synth per test. Bundling is disabled globally via `test/setup/disable-bundling.ts` (see Common mistakes).

## Primary locations

| Path | Access | Purpose |
|------|--------|---------|
| `cdk/src/handlers/` | WRITE | Lambda handlers |
| `cdk/src/stacks/` | WRITE | Stack definitions |
| `cdk/src/constructs/` | WRITE | Reusable constructs |
| `cdk/src/handlers/shared/types.ts` | WRITE | API types (mirror to `cli/src/types.ts`) |
| `cdk/test/` | WRITE | Unit / snapshot tests |
| `cli/src/types.ts` | WRITE (sync) | Must match shared types |

## Code style

**API responses** — use `successResponse` / `errorResponse` from `shared/response.ts`; never hand-roll JSON envelopes:

```typescript
// ✅ Good — contract envelope + typed ErrorCode
import { successResponse, errorResponse, ErrorCode } from '../shared/response';

return successResponse(200, { task_id: taskId }, requestId);
return errorResponse(422, ErrorCode.VALIDATION_ERROR, 'Invalid workflow_ref', requestId);

// ❌ Bad — ad-hoc body, no request ID
return { statusCode: 400, body: JSON.stringify({ error: 'bad' }) };
```

**Unit tests** — colocate under `cdk/test/`, descriptive `describe`/`test` names:

```typescript
// ✅ Good
describe('parseBody', () => {
test('returns null for invalid JSON', () => {
expect(parseBody('not json')).toBeNull();
});
});

// ❌ Bad — vague name, no edge cases
test('works', () => { expect(parseBody('{}')).toBeTruthy(); });
```

**Construct tests** — cache synth output:

```typescript
// ✅ Good
let template: Template;
beforeAll(() => {
const app = new App();
template = Template.fromStack(new MyStack(app, 'Test'));
});
```

## Boundaries

- ✅ **Always:** Update `cli/src/types.ts` when changing `shared/types.ts`; add/extend tests in `cdk/test/`; use mise tasks not raw `cdk` CLI
- ⚠️ **Ask first:** New stacks or constructs, IAM policy changes, DynamoDB schema changes, enabling Lambda bundling in unit tests
- 🚫 **Never:** Bump `@cedar-policy/cedar-wasm` without bumping `cedarpy` and refreshing `contracts/cedar-parity/` fixtures; re-enable global Lambda bundling in tests; use constructor `context` for `aws:cdk:bundling-stacks` (use `postCliContext` instead — see #366)

## Common mistakes

- **Lambda bundling in unit tests** — `Template.fromStack()` synths the stack but bundling is disabled via `CDK_CONTEXT_JSON`. Do not re-enable globally; opt in per-test with `postCliContext` only when asserting on bundle output. Details: `test/setup/disable-bundling.ts`, #366.
- **Cedar engine drift** — `@cedar-policy/cedar-wasm` and `cedarpy` share a Rust core. Bump both + parity fixtures in one commit. See `docs/design/CEDAR_HITL_GATES.md` §15.6 and `mise.toml` parity banner.
- **Types out of sync** — `cdk/src/handlers/shared/types.ts` and `cli/src/types.ts` must match; CI runs `check-types-sync`.
85 changes: 85 additions & 0 deletions cli/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# CLI package — agent context

Parent guide: [../AGENTS.md](../AGENTS.md)

You maintain the **`bgagent` CLI** (`@backgroundagent/cli`): Commander commands, Cognito auth, HTTP client, and API types mirrored from CDK.

## Commands (run these)

```bash
mise //cli:build # compile + test + lint
cd cli && mise run test # Jest only
cd cli && mise run compile # tsc only
mise //cli:eslint # ESLint --fix (run after merging main)
```

## Testing

- **Full suite:** `cd cli && mise run test` or `mise //cli:build`
- **Single file:** `cd cli && npx jest test/commands/status.test.ts`
- **Pattern:** `cd cli && npx jest --testPathPattern=auth`

Mock `ApiClient` in command tests; reset `process.exitCode` in `beforeEach`/`afterEach` (commands set exit codes — see `status.test.ts`).

## Primary locations

| Path | Access | Purpose |
|------|--------|---------|
| `cli/src/bin/bgagent.ts` | WRITE | Commander entry point |
| `cli/src/commands/` | WRITE | One file per subcommand |
| `cli/src/api-client.ts` | WRITE | Authenticated `fetch` wrapper |
| `cli/src/auth.ts` | WRITE | Cognito login, token cache (`~/.bgagent/credentials.json`) |
| `cli/src/types.ts` | WRITE | API types (mirror of `cdk/.../types.ts`) |
| `cli/test/` | WRITE | Jest tests |

## Code style

**New command** — factory function + `Command` from commander; throw `CliError` for user-facing errors:

```typescript
// ✅ Good — factory, validated options, CliError
import { Command } from 'commander';
import { CliError } from '../errors';

export function makeStatusCommand(): Command {
return new Command('status')
.argument('<task-id>', 'Task ID')
.option('--output <format>', 'text or json', 'text')
.action(async (taskId: string, opts) => {
if (!taskId) throw new CliError('Task ID is required.');
// ...
});
}

// ❌ Bad — side effects at import, console.error + process.exit
export const status = new Command('status').action(() => {
console.error('failed'); process.exit(1);
});
```

**Command tests** — mock `ApiClient`, spy `console.log`:

```typescript
// ✅ Good
jest.mock('../../src/api-client');
beforeEach(() => { process.exitCode = undefined; });

test('renders snapshot from combined payload', async () => {
mockGetStatusSnapshot.mockResolvedValue({ task: { task_id: 'abc', status: 'RUNNING', ... } });
await program.parseAsync(['node', 'status', 'abc']);
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('RUNNING'));
});
```

**Conventions:** `no-console` ESLint rule is disabled in CLI source (console output is the product). API URL from stack output includes `/v1/` — append only resource paths (`/tasks`, `/tasks/{id}`).

## Boundaries

- ✅ **Always:** Add tests in `cli/test/` for new commands; keep `types.ts` in sync with CDK; use `CliError` / `ApiError` for failures
- ⚠️ **Ask first:** New runtime dependencies, changes to auth/token storage format
- 🚫 **Never:** Change `cli/src/types.ts` without updating `cdk/src/handlers/shared/types.ts`; hardcode API URLs with stage prefix duplicated

## Common mistakes

- **API type drift** — Update both `cli/src/types.ts` and `cdk/src/handlers/shared/types.ts` in the same PR. See [cdk/AGENTS.md](../cdk/AGENTS.md).
- **Exit code leaks** — Command tests must reset `process.exitCode` or Jest exits non-zero despite green assertions.
70 changes: 70 additions & 0 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Docs package — agent context

Parent guide: [../AGENTS.md](../AGENTS.md)

You are a **technical writer for ABCA**: source guides and design docs, ADRs, and Starlight site mirrors. Write for developers new to the codebase — concise, specific, value-dense.

## Commands (run these)

```bash
mise //docs:sync # regenerate docs/src/content/docs/ (<1 s)
mise //docs:build # sync + Astro/Starlight build
mise //docs:check # sync + astro check (MDX/components)
```

Pre-commit hook `docs-sync` runs sync automatically when prek hooks are installed.

## Testing

- **Sync + build:** `mise //docs:build` (required before PR if you touched guides, design, ADRs, or `CONTRIBUTING.md`)
- **Sync only:** `mise //docs:sync` then `git diff docs/src/content/docs/` — commit mirror changes alongside sources
- **Astro check:** `mise //docs:check` (or `cd docs && npm run docs:check`)

CI **"Fail build on mutation"** rejects PRs where committed Starlight mirrors do not match what sync produces.

## Primary locations

| Path | Access | Purpose |
|------|--------|---------|
| `docs/guides/` | WRITE | User and developer guides |
| `docs/design/` | WRITE | Architecture and design docs |
| `docs/decisions/` | WRITE | ADRs |
| `docs/imgs/` | WRITE | Static images |
| `CONTRIBUTING.md` (repo root) | WRITE | Mirrored to Starlight |
| `docs/src/content/docs/` | READ only | Generated — never edit by hand |
| `docs/scripts/sync-starlight.mjs` | READ | Sync logic (change only if adding new mirror rules) |

Site renders `docs/design/` at `/architecture/` on the published docs site.

## Code style

**Edit source, then sync** — write guides in `docs/guides/`, not the Starlight mirror:

```markdown
<!-- ✅ Good — edit docs/guides/DEVELOPER_GUIDE.md -->
For routing and pitfalls, see **[AGENTS.md](../../AGENTS.md)** at the repo root.

Then run: `mise //docs:sync` and commit both source and `docs/src/content/docs/` changes.
```

```markdown
<!-- ❌ Bad — editing the generated mirror directly -->
<!-- File: docs/src/content/docs/developer-guide/Contributing.md -->
<!-- CI will fail or your edit will be overwritten on next sync -->
```

**Cross-links** — prefer relative links in source (`../../AGENTS.md`, `../design/ARCHITECTURE.md`); sync rewrites them for the site.

**ADRs** — add under `docs/decisions/`, follow existing naming (`ADR-NNN-title.md`), run sync.

## Boundaries

- ✅ **Always:** Edit `docs/guides/`, `docs/design/`, or `docs/decisions/`; run `mise //docs:sync` and commit mirrors; keep links relative in sources
- ⚠️ **Ask first:** Major IA changes, new top-level guide sections, editing `sync-starlight.mjs` mirror rules
- 🚫 **Never:** Edit `docs/src/content/docs/` by hand; skip sync after source changes; promise unshipped platform features without labeling them future

## Common mistakes

- **Stale mirrors** — Source changed but `docs/src/content/docs/` not regenerated → CI mutation failure.
- **Wrong tree** — `docs/design/` is authoritative; the Starlight copy under `architecture/` is generated.
- **CONTRIBUTING.md** — Root file is mirrored; sync after edits.
2 changes: 1 addition & 1 deletion docs/guides/DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Before editing, decide which part of the monorepo owns the behavior. This keeps
| Agent runtime | `agent/` | Bundled into the image CDK deploys; run `mise run quality` in `agent/` or root build. |
| Docs (source) | `docs/guides/`, `docs/design/` | After edits, run **`mise //docs:sync`** or **`mise //docs:build`**. Do not edit `docs/src/content/docs/` directly. |

For a concise duplicate of this table, common pitfalls, and a CDK test file map, see **[AGENTS.md](../../AGENTS.md)** at the repo root (oriented toward automation-assisted contributors).
For a concise duplicate of this table, common pitfalls, and a CDK test file map, see **[AGENTS.md](../../AGENTS.md)** at the repo root (oriented toward automation-assisted contributors). Package-specific detail lives in **`AGENTS.md`** under `cdk/`, `cli/`, `agent/`, and `docs/`.

## Repository preparation

Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/developer-guide/Contributing.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ Before editing, decide which part of the monorepo owns the behavior. This keeps
| Agent runtime | `agent/` | Bundled into the image CDK deploys; run `mise run quality` in `agent/` or root build. |
| Docs (source) | `docs/guides/`, `docs/design/` | After edits, run **`mise //docs:sync`** or **`mise //docs:build`**. Do not edit `docs/src/content/docs/` directly. |

For a concise duplicate of this table, common pitfalls, and a CDK test file map, see **[AGENTS.md](/sample-autonomous-cloud-coding-agents/architecture/agents)** at the repo root (oriented toward automation-assisted contributors).
For a concise duplicate of this table, common pitfalls, and a CDK test file map, see **[AGENTS.md](/sample-autonomous-cloud-coding-agents/architecture/agents)** at the repo root (oriented toward automation-assisted contributors). Package-specific detail lives in **`AGENTS.md`** under `cdk/`, `cli/`, `agent/`, and `docs/`.
Loading