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>
5 KiB
RFC 0032: Per-Repo AWS Profile Configuration
| Status | Draft |
| Date | 2026-01-26 |
| Dialogue | 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:
- No mechanism exists to declare which AWS profile a repo expects
- Claude's bash commands inherit whatever
AWS_PROFILEis set in the user's shell - Worktree isolation (
blue_env_mock) doesn't inject AWS profile settings - 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:
forge:
type: github
host: ...
owner: superviber
repo: blue
aws:
profile: cultivarium # AWS profile name from ~/.aws/config
Precedence Rules
- Shell
AWS_PROFILEalways wins (standard AWS CLI behavior) - Config provides repo default for Blue's process and
.env.isolated - CI/CD sets its own
AWS_PROFILEexternally
Rust Implementation
1. Add AwsConfig to BlueConfig
File: crates/blue-core/src/forge/mod.rs
#[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()
// 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()
// 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:
- Set
AWS_PROFILEin their shell before launching Claude Code desktop app - Use
--profileflags 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
awssection to test config, verifyBlueConfigdeserializes it - Verify
ensure_state()setsAWS_PROFILEwhen config present - Verify
ensure_state()respects existing shellAWS_PROFILE - Verify
blue_env_mockincludesAWS_PROFILEin.env.isolated - Verify startup diagnostic logs active profile
- Verify warning when shell profile differs from config
Alternatives Considered
-
Environment-specific profiles (
aws.profiles.{dev,ci,prod}) — Rejected as over-engineering; CI should set its own profile externally. -
Store in
.env.example— Rejected; config.yaml is the single source of truth for repo settings. -
Enforce profile (override shell) — Rejected; violates standard AWS CLI precedence and surprises operators.
"Right then. Let's get to it."
— Blue