feat(security): add GIT_AUTHOR_EMAIL per agent type #2
@@ -49,36 +49,43 @@ func AgentEnv(cfg AgentEnvConfig) map[string]string {
|
||||
case "mayor":
|
||||
env["BD_ACTOR"] = "mayor"
|
||||
env["GIT_AUTHOR_NAME"] = "mayor"
|
||||
env["GIT_AUTHOR_EMAIL"] = "mayor@gastown.local"
|
||||
|
||||
case "deacon":
|
||||
env["BD_ACTOR"] = "deacon"
|
||||
env["GIT_AUTHOR_NAME"] = "deacon"
|
||||
env["GIT_AUTHOR_EMAIL"] = "deacon@gastown.local"
|
||||
|
||||
case "boot":
|
||||
env["BD_ACTOR"] = "deacon-boot"
|
||||
env["GIT_AUTHOR_NAME"] = "boot"
|
||||
env["GIT_AUTHOR_EMAIL"] = "boot@gastown.local"
|
||||
|
||||
case "witness":
|
||||
env["GT_RIG"] = cfg.Rig
|
||||
env["BD_ACTOR"] = fmt.Sprintf("%s/witness", cfg.Rig)
|
||||
env["GIT_AUTHOR_NAME"] = fmt.Sprintf("%s/witness", cfg.Rig)
|
||||
env["GIT_AUTHOR_EMAIL"] = fmt.Sprintf("%s-witness@gastown.local", cfg.Rig)
|
||||
|
||||
case "refinery":
|
||||
env["GT_RIG"] = cfg.Rig
|
||||
env["BD_ACTOR"] = fmt.Sprintf("%s/refinery", cfg.Rig)
|
||||
env["GIT_AUTHOR_NAME"] = fmt.Sprintf("%s/refinery", cfg.Rig)
|
||||
env["GIT_AUTHOR_EMAIL"] = fmt.Sprintf("%s-refinery@gastown.local", cfg.Rig)
|
||||
|
||||
case "polecat":
|
||||
env["GT_RIG"] = cfg.Rig
|
||||
env["GT_POLECAT"] = cfg.AgentName
|
||||
env["BD_ACTOR"] = fmt.Sprintf("%s/polecats/%s", cfg.Rig, cfg.AgentName)
|
||||
env["GIT_AUTHOR_NAME"] = cfg.AgentName
|
||||
env["GIT_AUTHOR_EMAIL"] = fmt.Sprintf("%s-polecat-%s@gastown.local", cfg.Rig, cfg.AgentName)
|
||||
|
||||
case "crew":
|
||||
env["GT_RIG"] = cfg.Rig
|
||||
env["GT_CREW"] = cfg.AgentName
|
||||
env["BD_ACTOR"] = fmt.Sprintf("%s/crew/%s", cfg.Rig, cfg.AgentName)
|
||||
env["GIT_AUTHOR_NAME"] = cfg.AgentName
|
||||
env["GIT_AUTHOR_EMAIL"] = fmt.Sprintf("%s-crew-%s@gastown.local", cfg.Rig, cfg.AgentName)
|
||||
}
|
||||
|
||||
// Only set GT_ROOT if provided
|
||||
|
||||
@@ -14,6 +14,7 @@ func TestAgentEnv_Mayor(t *testing.T) {
|
||||
assertEnv(t, env, "GT_ROLE", "mayor")
|
||||
assertEnv(t, env, "BD_ACTOR", "mayor")
|
||||
assertEnv(t, env, "GIT_AUTHOR_NAME", "mayor")
|
||||
assertEnv(t, env, "GIT_AUTHOR_EMAIL", "mayor@gastown.local")
|
||||
assertEnv(t, env, "GT_ROOT", "/town")
|
||||
assertNotSet(t, env, "GT_RIG")
|
||||
assertNotSet(t, env, "BEADS_NO_DAEMON")
|
||||
@@ -31,6 +32,7 @@ func TestAgentEnv_Witness(t *testing.T) {
|
||||
assertEnv(t, env, "GT_RIG", "myrig")
|
||||
assertEnv(t, env, "BD_ACTOR", "myrig/witness")
|
||||
assertEnv(t, env, "GIT_AUTHOR_NAME", "myrig/witness")
|
||||
assertEnv(t, env, "GIT_AUTHOR_EMAIL", "myrig-witness@gastown.local")
|
||||
assertEnv(t, env, "GT_ROOT", "/town")
|
||||
}
|
||||
|
||||
@@ -49,6 +51,7 @@ func TestAgentEnv_Polecat(t *testing.T) {
|
||||
assertEnv(t, env, "GT_POLECAT", "Toast")
|
||||
assertEnv(t, env, "BD_ACTOR", "myrig/polecats/Toast")
|
||||
assertEnv(t, env, "GIT_AUTHOR_NAME", "Toast")
|
||||
assertEnv(t, env, "GIT_AUTHOR_EMAIL", "myrig-polecat-Toast@gastown.local")
|
||||
assertEnv(t, env, "BEADS_AGENT_NAME", "myrig/Toast")
|
||||
assertEnv(t, env, "BEADS_NO_DAEMON", "1")
|
||||
}
|
||||
@@ -68,6 +71,7 @@ func TestAgentEnv_Crew(t *testing.T) {
|
||||
assertEnv(t, env, "GT_CREW", "emma")
|
||||
assertEnv(t, env, "BD_ACTOR", "myrig/crew/emma")
|
||||
assertEnv(t, env, "GIT_AUTHOR_NAME", "emma")
|
||||
assertEnv(t, env, "GIT_AUTHOR_EMAIL", "myrig-crew-emma@gastown.local")
|
||||
assertEnv(t, env, "BEADS_AGENT_NAME", "myrig/emma")
|
||||
assertEnv(t, env, "BEADS_NO_DAEMON", "1")
|
||||
}
|
||||
@@ -85,6 +89,7 @@ func TestAgentEnv_Refinery(t *testing.T) {
|
||||
assertEnv(t, env, "GT_RIG", "myrig")
|
||||
assertEnv(t, env, "BD_ACTOR", "myrig/refinery")
|
||||
assertEnv(t, env, "GIT_AUTHOR_NAME", "myrig/refinery")
|
||||
assertEnv(t, env, "GIT_AUTHOR_EMAIL", "myrig-refinery@gastown.local")
|
||||
assertEnv(t, env, "BEADS_NO_DAEMON", "1")
|
||||
}
|
||||
|
||||
@@ -98,6 +103,7 @@ func TestAgentEnv_Deacon(t *testing.T) {
|
||||
assertEnv(t, env, "GT_ROLE", "deacon")
|
||||
assertEnv(t, env, "BD_ACTOR", "deacon")
|
||||
assertEnv(t, env, "GIT_AUTHOR_NAME", "deacon")
|
||||
assertEnv(t, env, "GIT_AUTHOR_EMAIL", "deacon@gastown.local")
|
||||
assertEnv(t, env, "GT_ROOT", "/town")
|
||||
assertNotSet(t, env, "GT_RIG")
|
||||
assertNotSet(t, env, "BEADS_NO_DAEMON")
|
||||
@@ -113,6 +119,7 @@ func TestAgentEnv_Boot(t *testing.T) {
|
||||
assertEnv(t, env, "GT_ROLE", "boot")
|
||||
assertEnv(t, env, "BD_ACTOR", "deacon-boot")
|
||||
assertEnv(t, env, "GIT_AUTHOR_NAME", "boot")
|
||||
assertEnv(t, env, "GIT_AUTHOR_EMAIL", "boot@gastown.local")
|
||||
assertEnv(t, env, "GT_ROOT", "/town")
|
||||
assertNotSet(t, env, "GT_RIG")
|
||||
assertNotSet(t, env, "BEADS_NO_DAEMON")
|
||||
|
||||
@@ -35,7 +35,9 @@ drive shaft - if you stall, the whole town stalls.
|
||||
**Your startup behavior:**
|
||||
1. Check hook (`gt hook`)
|
||||
2. If work is hooked → EXECUTE (no announcement beyond one line, no waiting)
|
||||
3. If hook empty → Check mail, then wait for user instructions
|
||||
3. If hook empty → Check escalations (`gt escalate list`)
|
||||
4. Handle any pending escalations (these are urgent items from other agents)
|
||||
5. Check mail, then wait for user instructions
|
||||
|
||||
**Note:** "Hooked" means work assigned to you. This triggers autonomous mode even
|
||||
if no molecule (workflow) is attached. Don't confuse with "pinned" which is for
|
||||
@@ -241,16 +243,21 @@ Like crew, you're human-managed. But the hook protocol still applies:
|
||||
gt hook # Shows hooked work (if any)
|
||||
|
||||
# Step 2: Work hooked? → RUN IT
|
||||
# Hook empty? → Check mail for attached work
|
||||
|
||||
# Step 3: Hook empty? → Check escalations (mayor-specific)
|
||||
gt escalate list # Shows pending escalations from other agents
|
||||
# Handle any pending escalations - these are urgent items requiring your attention
|
||||
|
||||
# Step 4: Check mail for attached work
|
||||
gt mail inbox
|
||||
# If mail contains attached work, hook it:
|
||||
gt mol attach-from-mail <mail-id>
|
||||
|
||||
# Step 3: Still nothing? Wait for user instructions
|
||||
# Step 5: Still nothing? Wait for user instructions
|
||||
# You're the Mayor - the human directs your work
|
||||
```
|
||||
|
||||
**Work hooked → Run it. Hook empty → Check mail. Nothing anywhere → Wait for user.**
|
||||
**Work hooked → Run it. Hook empty → Check escalations → Check mail. Nothing anywhere → Wait for user.**
|
||||
|
||||
Your hooked work persists across sessions. Handoff mail (🤝 HANDOFF subject) provides context notes.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user