Documentation
¶
Overview ¶
Package project manages per-project configuration and lifecycle state.
Each island is represented by a project: (name, repo, agent, resources, desired state). Config persists to ~/.dejima/projects/<name>/config.toml.
Index ¶
- Constants
- func Delete(name string) error
- func DeriveNameFromRepo(repo string) string
- func EnsureProjectSubdirs(name string) error
- func Exists(name string) bool
- func PrimaryAgentID(name string) string
- func ValidateCapabilityTarget(target string) error
- func ValidateName(name string) error
- type AgentSpec
- type CapabilityGrant
- type MCPGrant
- type PortScope
- type Project
- func (p *Project) AddAgent(spec AgentSpec)
- func (p *Project) AddCapabilityGrant(g CapabilityGrant) (CapabilityGrant, error)
- func (p *Project) AddLinkAction(action string) bool
- func (p *Project) AddPortScope(s PortScope) (PortScope, error)
- func (p *Project) AgentByID(id string) (*AgentSpec, bool)
- func (p *Project) CapabilityGrantByTarget(target string) (CapabilityGrant, bool)
- func (p *Project) ContainerName() string
- func (p *Project) DisplayName() string
- func (p *Project) EnsureAgents()
- func (p *Project) ExposesAction(action string) bool
- func (p *Project) HomeVolume() string
- func (p *Project) IsHome() bool
- func (p *Project) NetworkName() string
- func (p *Project) NextAgentID() string
- func (p *Project) PortScopeByHostPath(hostPath string) (*PortScope, bool)
- func (p *Project) PortScopeByName(name string) (*PortScope, bool)
- func (p *Project) PrimaryAgent() *AgentSpec
- func (p *Project) RemoveAgent(id string) bool
- func (p *Project) RemoveCapabilityGrant(target string) (CapabilityGrant, bool)
- func (p *Project) RemoveLinkAction(action string) bool
- func (p *Project) RemovePortScope(key string) (PortScope, bool)
- func (p *Project) Save() error
- func (p *Project) SetPrimaryID(id string)
- func (p *Project) WorkspaceVolume() string
- type Resources
- type State
Constants ¶
const ( PortModeRO = "ro" PortModeRW = "rw" )
Port access modes. V1 grants are read-only; "rw" is reserved for the read-write milestone (docs/port-island-spec.md §6) and rejected at grant time until then.
const ( RoleProject = "" RoleHome = "home" )
Island roles. Empty (RoleProject) is the default work/coding island. RoleHome marks a persistent "Home Island" that hosts an always-on assistant orchestrator (the brain), which reaches host content only through the Port and spawns work islands via the API. See docs/port-island-spec.md §3.2.
Variables ¶
This section is empty.
Functions ¶
func DeriveNameFromRepo ¶
DeriveNameFromRepo extracts a reasonable default name from a repo URL or path.
func EnsureProjectSubdirs ¶
EnsureProjectSubdirs creates intake/, exports/, logs/ for a project.
func PrimaryAgentID ¶
PrimaryAgentID is the id a brand-new island's primary agent gets: the island's mnemonic letter + "1" (e.g. "Port" → "p1"), matching the scheme NextAgentID uses for added agents. Legacy islands migrated by EnsureAgents keep "a1" so a live attached session isn't renamed out from under the user.
func ValidateCapabilityTarget ¶
ValidateCapabilityTarget checks a capability target name — a macOS Shortcut name or a ~/.dejima/capabilities/ script basename. It is intentionally more permissive than ValidateName (real Shortcut names carry spaces and mixed case) but stays safe as a single filename component: no path separators or traversal, no control characters, bounded length. The strict mode/ownership checks for the Linux script adapter happen at execution time, not here.
func ValidateName ¶
ValidateName ensures a name is safe to use in container/volume names.
Types ¶
type AgentSpec ¶
type AgentSpec struct {
ID string `toml:"id"` // stable per-island handle: "a1", "a2", …
Type string `toml:"type"` // handler id: "claude-code", "codex", "headless"
// Label is a user-facing, renamable name (e.g. "frontend"). Cosmetic.
Label string `toml:"label,omitempty"`
// Cmd is the entrypoint for headless agents; empty for the CLI agents.
Cmd string `toml:"cmd,omitempty"`
// Tmux is the in-container tmux session name for interactive agents. Empty
// for headless. The migrated primary keeps "dejima" so a live attached
// session survives a daemon upgrade; new agents use "agent-<id>".
Tmux string `toml:"tmux,omitempty"`
// Branch is the git branch backing this agent's worktree.
Branch string `toml:"branch,omitempty"`
// Worktree is the container path the agent works in: "/workspace" for the
// primary, "/workspace/.agents/<id>" for the rest.
Worktree string `toml:"worktree,omitempty"`
// Restart enables supervise-and-restart-on-crash for co-located headless agents.
Restart bool `toml:"restart,omitempty"`
// Provider names which daemon LLM-provider credential this agent uses (see
// internal/providercreds), e.g. "anthropic". Empty → the store default. Only
// meaningful when the handler RequiresProviderKey.
Provider string `toml:"provider,omitempty"`
// Model is the "provider/model" string handed to the framework (via the
// DEJIMA_MODEL env the per-agent shim translates). Empty → unset (the user
// picks explicitly; there is no baked-in default).
Model string `toml:"model,omitempty"`
CreatedAt time.Time `toml:"created_at,omitempty"`
}
AgentSpec is one agent running inside an island. An island hosts one or more agents; the first is the "primary" (the attach target for legacy clients).
type CapabilityGrant ¶
type CapabilityGrant struct {
Target string `toml:"target"`
GrantedAt time.Time `toml:"granted_at"`
}
CapabilityGrant is an island's permission to invoke one named host capability target — a macOS Shortcut, or an executable in ~/.dejima/capabilities/ on Linux. Deny-all is the default: an island may invoke only the targets granted here. The adapter that runs a target is chosen by host OS at execution time, not stored per grant. See docs/capability-broker-spec.md.
type MCPGrant ¶
MCPGrant is an island's permission to invoke one named, host-curated MCP server (an entry in ~/.dejima/mcp/servers.toml — see internal/mcpbroker). The transport and command behind the name are chosen host-side, not stored per grant; the grant is only the island↦server-name permission.
func AddMCPGrant ¶
AddMCPGrant records a grant, rejecting a duplicate server name. The server name is validated by the caller (mcpbroker.ValidateServerName).
func MCPGrantByServer ¶
MCPGrantByServer returns the grant for server, or ok=false.
func MCPGrantsFor ¶
MCPGrantsFor returns an island's MCP-server grants (empty ⇒ deny-all). A missing sidecar is the deny-all default, not an error.
type PortScope ¶
type PortScope struct {
// Name is the short, slug handle used to address the scope in Trades and the
// Ledger (e.g. "vault"). Derived from the host path's basename; unique within
// the island.
Name string `toml:"name"`
// HostPath is the absolute host directory granted. The broker never serves
// anything outside it.
HostPath string `toml:"host_path"`
// Mode is "ro" or "rw".
Mode string `toml:"mode"`
GrantedAt time.Time `toml:"granted_at"`
}
PortScope is a single brokered host-filesystem grant for an island: a host directory the Port broker may Trade files from/to, and the policy on it.
Access is deny-all by default — an island reaches host content only through an explicit scope. Scopes live in the island's host-side config (0600) and are never writable from inside the island, so an island cannot widen its own grant.
type Project ¶
type Project struct {
Name string `toml:"name"`
// Title is a cosmetic, freely-editable display name. Name stays the durable
// infra handle (container/volume/network/config-dir identity, and the slug
// addressed by the CLI); Title is what the user reads. Empty → show Name.
Title string `toml:"title,omitempty"`
RepoURL string `toml:"repo"`
// Agent and Cmd are the pre-multi-agent scalar fields. They are retained for
// backward compatibility (older daemons read them) and mirror Agents[0]. New
// code should read Agents; PrimaryAgent() is the accessor.
Agent string `toml:"agent"`
Image string `toml:"image"`
// Cmd is the command to run inside the island when Agent is "headless".
// It is ignored for the built-in CLI agents (claude-code, codex), which
// have a baked-in command. Persisted so reset/reprovision can reuse it.
Cmd string `toml:"cmd,omitempty"`
Resources Resources `toml:"resources,omitempty"`
CreatedAt time.Time `toml:"created_at"`
LastUsedAt time.Time `toml:"last_used_at"`
DesiredState State `toml:"state"`
Agents []AgentSpec `toml:"agents,omitempty"`
// Role is the island's purpose: "" (a work island) or "home" (a Home Island
// hosting an assistant brain). Empty for islands created before roles existed.
Role string `toml:"role,omitempty"`
// GitHubIdentity names which of the daemon's GitHub identities this island
// clones and pushes as (see internal/githubid). Empty means the daemon's
// default identity, or — when the store is empty — the host's ~/.config/gh.
GitHubIdentity string `toml:"github_identity,omitempty"`
// Ports are brokered host-filesystem grants for this island (see ports.go).
// Empty means deny-all: the island reaches no host content outside its repo.
Ports []PortScope `toml:"ports,omitempty"`
// Capabilities are brokered host-action grants for this island (see
// capabilities.go and docs/capability-broker-spec.md). Empty means deny-all:
// the island may invoke no host capabilities.
Capabilities []CapabilityGrant `toml:"capabilities,omitempty"`
// LinkActions are the named, typed action types THIS island exposes for
// cross-island delegation (Lane 5, Phase 3). Another island may invoke one of
// these only if it ALSO holds a link grant authorizing it (or an operator
// approves ad hoc). Empty means deny-all: this island exposes no actions.
LinkActions []string `toml:"link_actions,omitempty"`
// Owner is a free-form creator label (e.g. "alice@laptop"), captured at
// create time. Purely informational — there is no auth model yet — but it
// lets wrapper dashboards attribute islands per person/team. Empty for
// islands created before ownership existed.
Owner string `toml:"owner,omitempty"`
// Tags are free-form key=value labels (e.g. team=web, env=staging) for
// grouping and per-team rollups in wrapper tooling. Empty when untagged.
Tags map[string]string `toml:"tags,omitempty"`
}
Project is the persisted record for a single island.
func (*Project) AddCapabilityGrant ¶
func (p *Project) AddCapabilityGrant(g CapabilityGrant) (CapabilityGrant, error)
AddCapabilityGrant records a grant, rejecting a duplicate target. The target is validated by the caller (see ValidateCapabilityTarget).
func (*Project) AddLinkAction ¶
AddLinkAction exposes action (idempotent). Returns false if already exposed.
func (*Project) AddPortScope ¶
AddPortScope cleans the host path, assigns a unique Name, and appends the scope. It errors if the host path is already granted. Returns the stored scope (with its assigned Name).
func (*Project) CapabilityGrantByTarget ¶
func (p *Project) CapabilityGrantByTarget(target string) (CapabilityGrant, bool)
CapabilityGrantByTarget returns the grant for target, or ok=false.
func (*Project) ContainerName ¶
ContainerName returns the deterministic container name for this project.
func (*Project) DisplayName ¶
DisplayName is the user-facing name: the Title if set, else the Name slug.
func (*Project) EnsureAgents ¶
func (p *Project) EnsureAgents()
EnsureAgents back-fills Agents from the legacy scalar Agent field for projects persisted under the pre-multi-agent schema. Idempotent: a no-op once Agents is populated. Called on Load and at provision time.
func (*Project) ExposesAction ¶
ExposesAction reports whether this island exposes the named action type for cross-island delegation (Lane 5, Phase 3). Deny-all: an unexposed action can never be invoked, even with a link grant.
func (*Project) HomeVolume ¶
HomeVolume returns the per-island home-state volume, mounted at /home/dejima and shared by every agent in the island. Persisting the whole home means tool auth set once by any agent (Claude/Codex creds, ~/.npmrc, gh, eas/expo) survives restarts and is shared — the "collective permissioning" goal.
func (*Project) IsHome ¶
IsHome reports whether this island is a Home Island (hosts an assistant brain).
func (*Project) NetworkName ¶
NetworkName returns the per-island Docker network name.
func (*Project) NextAgentID ¶
NextAgentID returns the next monotonic "<letter><N>" id not currently in use. The letter is the island's mnemonic prefix (see agentIDPrefix), so an island named "Port" yields p1, p2, …. Ids are scoped per island and never reused within an island's life, so a removed agent's id stays retired. Numbering is monotonic across whatever prefixes already exist, so a legacy island that holds a1/a2 simply continues at the new prefix (p3).
func (*Project) PortScopeByHostPath ¶
PortScopeByHostPath returns the scope for the given (cleaned) host path.
func (*Project) PortScopeByName ¶
PortScopeByName returns the scope with the given handle.
func (*Project) PrimaryAgent ¶
PrimaryAgent returns the island's first/primary agent (the attach target for legacy clients), or nil if the island has no agents.
func (*Project) RemoveAgent ¶
RemoveAgent drops the agent with the given id. Reports whether it was found.
func (*Project) RemoveCapabilityGrant ¶
func (p *Project) RemoveCapabilityGrant(target string) (CapabilityGrant, bool)
RemoveCapabilityGrant removes the grant for target; ok=false if not present.
func (*Project) RemoveLinkAction ¶
RemoveLinkAction unexposes action. Returns false if it wasn't exposed.
func (*Project) RemovePortScope ¶
RemovePortScope drops the scope identified by key, which may be either its Name or its (cleaned) host path. Reports the removed scope and whether found.
func (*Project) SetPrimaryID ¶
SetPrimaryID renames the primary agent's id and the tmux session derived from it. Intended for fresh provision only — before any container or session exists — so it deliberately does not migrate a running session.
func (*Project) WorkspaceVolume ¶
WorkspaceVolume returns the workspace volume name.
type Resources ¶
type Resources struct {
Memory string `toml:"memory,omitempty"` // e.g. "4G"
CPUs string `toml:"cpus,omitempty"` // e.g. "2.0"
Disk string `toml:"disk,omitempty"` // e.g. "20G" — maps to --storage-opt size=
// OOMPriority stack-ranks islands for the kernel OOM killer: higher = more
// protected (killed later). nil = unset → resolved to a smart default at
// create (headless brains start expendable). Mapped to docker --oom-score-adj
// (inverted) in the api layer. Set-at-create only; a change needs a recreate.
OOMPriority *int `toml:"oom_priority,omitempty"`
}
Resources captures the docker resource caps applied to the container. All fields optional; zero/empty means unlimited.