ADRs: - Update 0008-honor, 0009-courage, 0013-overflow, 0015-plausibility - Add 0017-hosted-coding-assistant-architecture RFCs: - 0032: per-repo AWS profile configuration (draft) - 0033: round-scoped dialogue files (impl + plan) - 0034: comprehensive config architecture (accepted) - 0036: expert output discipline (impl) - 0037: single source protocol authority (draft) - 0038: SDLC workflow discipline (draft) - 0039: ADR architecture greenfield clarifications (impl) - 0040: divorce financial analysis (draft) - 0042: alignment dialogue defensive publication (draft) Spikes: - Read tool token limit on assembled dialogues - RFC ID collision root cause - Expert agent output too long - Judge writes expert outputs - Blue MCP server on superviber infrastructure - Playwright MCP multiple window isolation Dialogues: 16 alignment dialogue records Code: - blue-core: forge module enhancements - blue-mcp: env handlers and server updates - alignment-expert agent improvements - alignment-play skill refinements - install.sh script Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
156 lines
5 KiB
Markdown
156 lines
5 KiB
Markdown
# RFC 0032: Per-Repo AWS Profile Configuration
|
|
|
|
| | |
|
|
|---|---|
|
|
| **Status** | Draft |
|
|
| **Date** | 2026-01-26 |
|
|
| **Dialogue** | [aws-profile-config.dialogue.md](../dialogues/2026-01-26T0700Z-aws-profile-config.dialogue.md) |
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
Blue needs a way to configure per-repo AWS profiles in `.blue/config.yaml` so that all AWS operations during a Claude Code session use the correct credentials. Different repos require different AWS profiles (e.g., `f-i-a` uses `cultivarium`, `hearth`/`aperture` use `muffinlabs`).
|
|
|
|
## Problem
|
|
|
|
When working across multiple repositories that deploy to different AWS accounts, developers and Claude Code sessions need to use the correct AWS profile for each repo. Currently:
|
|
|
|
1. No mechanism exists to declare which AWS profile a repo expects
|
|
2. Claude's bash commands inherit whatever `AWS_PROFILE` is set in the user's shell
|
|
3. Worktree isolation (`blue_env_mock`) doesn't inject AWS profile settings
|
|
4. First-run discovery is poor—new contributors don't know which profile to use
|
|
|
|
## Design
|
|
|
|
### Two-Layer Architecture
|
|
|
|
| Layer | Scope | Implementation |
|
|
|-------|-------|----------------|
|
|
| **Layer 1: Blue MCP** | Bash commands, Blue tools | `std::env::set_var("AWS_PROFILE", ...)` in `ensure_state()` |
|
|
| **Layer 2: Worktrees** | Isolated environments | `blue_env_mock` writes `AWS_PROFILE` to `.env.isolated` |
|
|
| **Layer 3: AWS MCP** | External server | User responsibility (documented limitation) |
|
|
|
|
### Config Schema
|
|
|
|
Add `aws` section to `.blue/config.yaml`, parallel to existing `forge`:
|
|
|
|
```yaml
|
|
forge:
|
|
type: github
|
|
host: ...
|
|
owner: superviber
|
|
repo: blue
|
|
|
|
aws:
|
|
profile: cultivarium # AWS profile name from ~/.aws/config
|
|
```
|
|
|
|
### Precedence Rules
|
|
|
|
1. **Shell `AWS_PROFILE` always wins** (standard AWS CLI behavior)
|
|
2. Config provides repo default for Blue's process and `.env.isolated`
|
|
3. CI/CD sets its own `AWS_PROFILE` externally
|
|
|
|
### Rust Implementation
|
|
|
|
#### 1. Add `AwsConfig` to `BlueConfig`
|
|
|
|
File: `crates/blue-core/src/forge/mod.rs`
|
|
|
|
```rust
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AwsConfig {
|
|
pub profile: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct BlueConfig {
|
|
pub forge: Option<ForgeConfig>,
|
|
pub aws: Option<AwsConfig>, // NEW
|
|
}
|
|
```
|
|
|
|
#### 2. Inject at MCP Server Startup
|
|
|
|
File: `crates/blue-mcp/src/server.rs` in `ensure_state()`
|
|
|
|
```rust
|
|
// After loading config, inject AWS_PROFILE into process environment
|
|
if let Some(aws) = &state.config.aws {
|
|
// Only set if not already present (respect shell override)
|
|
if std::env::var("AWS_PROFILE").is_err() {
|
|
std::env::set_var("AWS_PROFILE", &aws.profile);
|
|
tracing::info!(profile = %aws.profile, "AWS profile set for session");
|
|
} else {
|
|
let shell_profile = std::env::var("AWS_PROFILE").unwrap();
|
|
if shell_profile != aws.profile {
|
|
tracing::info!(
|
|
config_profile = %aws.profile,
|
|
shell_profile = %shell_profile,
|
|
"Shell AWS_PROFILE differs from config—using shell value"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3. Inject into `.env.isolated`
|
|
|
|
File: `crates/blue-mcp/src/handlers/env.rs` in `generate_env_isolated()`
|
|
|
|
```rust
|
|
// Add AWS profile from config if present
|
|
if let Some(aws) = &config.aws {
|
|
lines.push(format!("AWS_PROFILE={}", aws.profile));
|
|
}
|
|
```
|
|
|
|
### AWS MCP Server Limitation
|
|
|
|
The AWS MCP server (`mcp__aws-api__call_aws`) runs as a **separate process** that Blue cannot control. Users must either:
|
|
|
|
1. Set `AWS_PROFILE` in their shell **before** launching Claude Code desktop app
|
|
2. Use `--profile` flags explicitly in AWS CLI calls
|
|
|
|
This limitation should be documented in Blue's setup guide.
|
|
|
|
## Per-Repo Configuration
|
|
|
|
| Repo | Profile | Config |
|
|
|------|---------|--------|
|
|
| `f-i-a` | `cultivarium` | `aws: { profile: cultivarium }` |
|
|
| `hearth` | `muffinlabs` | `aws: { profile: muffinlabs }` |
|
|
| `aperture` | `muffinlabs` | `aws: { profile: muffinlabs }` |
|
|
|
|
## What Blue Controls vs. Documents
|
|
|
|
| Aspect | Blue Controls | Blue Documents |
|
|
|--------|---------------|----------------|
|
|
| Bash `aws` CLI commands | Yes | — |
|
|
| Blue MCP tools touching AWS | Yes | — |
|
|
| `.env.isolated` for worktrees | Yes | — |
|
|
| AWS MCP server (`call_aws`) | No | User sets shell env or `--profile` |
|
|
|
|
## Test Plan
|
|
|
|
- [ ] Add `aws` section to test config, verify `BlueConfig` deserializes it
|
|
- [ ] Verify `ensure_state()` sets `AWS_PROFILE` when config present
|
|
- [ ] Verify `ensure_state()` respects existing shell `AWS_PROFILE`
|
|
- [ ] Verify `blue_env_mock` includes `AWS_PROFILE` in `.env.isolated`
|
|
- [ ] Verify startup diagnostic logs active profile
|
|
- [ ] Verify warning when shell profile differs from config
|
|
|
|
## Alternatives Considered
|
|
|
|
1. **Environment-specific profiles** (`aws.profiles.{dev,ci,prod}`) — Rejected as over-engineering; CI should set its own profile externally.
|
|
|
|
2. **Store in `.env.example`** — Rejected; config.yaml is the single source of truth for repo settings.
|
|
|
|
3. **Enforce profile (override shell)** — Rejected; violates standard AWS CLI precedence and surprises operators.
|
|
|
|
---
|
|
|
|
*"Right then. Let's get to it."*
|
|
|
|
— Blue
|