feat(boss): Boss creates nests and assigns registry crows (#43)

This commit is contained in:
Smokey committed 2026-10-28 09:11:57 -06:00
1 parent 3e4b591762
commit dab245cb73
5 files changed
+106 -11

No files matched your search

+72 -3
View File
@@ -8,12 +8,16 @@ import (
)
// bossSystem is the Chief of Staff's contract. A spin-up order comes back on a
// SPIN line the harness reads and executes; anything else is plain talk.
// SPIN line and a nest order on a NEST line, both read and executed by the
// harness; anything else is plain talk.
const bossSystem = `You are Boss crow, the Chief of Staff of a flock of AI agents. You run the flock's schedule and keep its books.
When the owner asks you to spin up a new crow, your ENTIRE reply must start with this first line:
SPIN {"name":"<name>","persona":"<persona>","trust":"stranger|regular"}
Pick "persona" from the existing flock roster; a new crow only runs on an existing persona's habits. Starting trust is stranger or regular, never higher.
For anything else, reply in plain text. Do not use the SPIN line unless the owner asked for a new crow.`
When the owner asks you to create a nest, your ENTIRE reply must start with this first line:
NEST {"name":"<nest name>","crows":["<crow>","<crow>"]}
The crows are the working flock members the owner named; the Sentry, Elder, Quill and Boss serve every nest and are never members.
For anything else, reply in plain text. Do not use the SPIN or NEST line unless the owner asked for a new crow or a new nest.`
// spinOrder is the JSON after a "SPIN " prefix.
type spinOrder struct {
@@ -22,9 +26,16 @@ type spinOrder struct {
Trust string `json:"trust"`
}
// nestOrder is the JSON after a "NEST " prefix.
type nestOrder struct {
Name string `json:"name"`
Crows []string `json:"crows"`
}
// respondBoss answers a request addressed to Boss: one model call through the
// flock (CHATROOM_SPEC section 6). A SPIN reply is validated, written to the
// registry, and announced; a refusal says why. No reply posts nothing.
// registry, and announced; a NEST reply is validated and built through the
// nest store; a refusal says why. No reply posts nothing.
func (s *Server) respondBoss(nest Nest, req Message) {
budget := &Budget{name: "boss-command", limit: s.p.G.TokenBudgetPerItem}
system := systemFor("Boss", bossSystem, false)
@@ -34,11 +45,16 @@ func (s *Server) respondBoss(nest Nest, req Message) {
return // a flock that cannot answer says and does nothing
}
order, isSpin, reason := s.parseSpin(answer)
nOrder, isNest, nestReason := s.parseNest(answer)
switch {
case isSpin && reason == "":
s.spinCrow(nest, req, order)
case isSpin:
s.postBossSay(nest, req, order.Name, reason)
case isNest && nestReason == "":
s.createNest(nest, req, nOrder)
case isNest:
s.postBossSay(nest, req, nOrder.Name, nestReason)
default:
s.postBossSay(nest, req, "", strings.TrimSpace(answer))
}
@@ -82,6 +98,31 @@ func (s *Server) validPersona(name string) bool {
return ok
}
// parseNest reads a NEST reply. isNest says the reply was a nest order;
// reason, when not "", is why the order never reaches the nest store. Member
// names are resolved by the store itself: persona crows and registry crows
// pass, anything else (service roles included) is refused there.
func (s *Server) parseNest(answer string) (order nestOrder, isNest bool, reason string) {
text := strings.TrimSpace(answer)
if !strings.HasPrefix(text, "NEST ") {
return nestOrder{}, false, ""
}
if err := json.Unmarshal([]byte(strings.TrimSpace(strings.TrimPrefix(text, "NEST "))), &order); err != nil {
return nestOrder{}, true, "that order did not parse; try again."
}
order.Name = strings.TrimSpace(order.Name)
for i, c := range order.Crows {
order.Crows[i] = strings.TrimSpace(c)
}
switch {
case order.Name == "":
return order, true, "that order had no nest name in it."
case len(order.Crows) == 0:
return order, true, "that order had no crows in it."
}
return order, true, ""
}
// nameTaken checks the persona roster and the registry alike.
func (s *Server) nameTaken(name string) bool {
if s.validPersona(name) {
@@ -108,6 +149,34 @@ func (s *Server) spinCrow(nest Nest, req Message, order spinOrder) {
s.postBossSay(nest, req, order.Name, fmt.Sprintf("%s joined, running on %s's habits at %s.", order.Name, order.Persona, order.Trust))
}
// createNest builds the nest Boss was ordered into. The store has the last
// word on guardrails — name, members (persona roster or registry), duplicates
// and the nest cap are all checked there before anything mutates, so a bad
// order never leaves a partial nest. Success posts a Boss say announcing
// membership in the new nest, plus a confirming say in the requesting nest; a
// refusal says why.
func (s *Server) createNest(reqNest Nest, req Message, order nestOrder) {
created, err := s.nests.Create(order.Name, order.Crows)
if err != nil {
s.postBossSay(reqNest, req, order.Name, err.Error())
return
}
members := strings.Join(created.Crows, ", ")
open := Message{
NestID: created.ID,
Kind: "say",
Author: "Boss",
Text: fmt.Sprintf("This nest is open: %s. Its crows: %s.", created.Name, members),
To: req.Author,
TaggedBy: "harness",
Timestamp: time.Now().UTC().Format(time.RFC3339),
}
if record, err := s.msgs.Append(open); err == nil {
s.emitNestMessage(record)
}
s.postBossSay(reqNest, req, created.Name, fmt.Sprintf("%s opened with %s.", created.Name, members))
}
// postBossSay is Boss's one-line reply: an outcome or a refusal, always a say.
func (s *Server) postBossSay(nest Nest, req Message, name, text string) {
reply := Message{