Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
670fab3
feat(plugin): add agents plugin (first iteration)
yyovil Jun 1, 2026
73ed7af
Move agent adapters under backend adapters
yyovil Jun 1, 2026
7714f94
Keep daemon ports and session out of adapter move
yyovil Jun 1, 2026
908a879
Remove Better-AO naming from flake
yyovil Jun 1, 2026
8749d85
Keep flake as dev shell only
yyovil Jun 1, 2026
2dd0d6e
Use goimports for local formatting
yyovil Jun 1, 2026
8417c6d
Merge PR #65 (Add agents adapters, @yyovil) into staging
harshitsinghbhandari Jun 1, 2026
40f1976
feat(scm): GitHub provider adapter — Observe(prURL) → PRObservation
harshitsinghbhandari Jun 1, 2026
e0b8ab0
Merge PR #69 (feat(scm): GitHub provider adapter, aa-38) into staging
harshitsinghbhandari Jun 1, 2026
b463232
feat(daemon): wire Session Manager + agent shim + RepoResolver + inbo…
harshitsinghbhandari Jun 1, 2026
82e9111
Merge PR #70 (feat(daemon): wire SM + agent shim + RepoResolver + inb…
harshitsinghbhandari Jun 1, 2026
6bd4559
feat(ao): `ao spawn` CLI + POST /api/v1/sessions route
harshitsinghbhandari Jun 1, 2026
68f92dd
feat(observe): SCM poller — Observe → pr.Manager → lifecycle nudges
harshitsinghbhandari Jun 1, 2026
63cf526
Merge PR #72 (feat(observe): SCM poller, aa-41) into staging
harshitsinghbhandari Jun 1, 2026
26f49da
fix(ao): address PR γ review + clear inherited lint debt
harshitsinghbhandari Jun 1, 2026
e22a386
Merge remote-tracking branch 'origin/staging' into feat/ao-spawn-cli
harshitsinghbhandari Jun 1, 2026
f8ec354
fix(lint): lift loop condition in scm poller test (staticcheck QF1006)
harshitsinghbhandari Jun 1, 2026
e72b5b9
feat(ao): `ao spawn` CLI + POST /api/v1/sessions route (#71)
harshitsinghbhandari Jun 1, 2026
c162432
Merge PR #71 (feat(ao): ao spawn CLI + POST /api/v1/sessions route, a…
harshitsinghbhandari Jun 1, 2026
eb0ac00
scripts: add ao-here.sh — register cwd as a project and start the daemon
harshitsinghbhandari Jun 1, 2026
0e14340
scripts(ao-here): use built backend/cmd/ao binary explicitly, drop PA…
harshitsinghbhandari Jun 1, 2026
b6c76b4
fix(session): default branch to ao/<sessionID> when SpawnConfig.Branc…
harshitsinghbhandari Jun 1, 2026
baa386f
fix(ao-here): correct jq path for 409 existingProjectId
harshitsinghbhandari Jun 1, 2026
d9cd52b
Merge origin/main: adopt session_manager/service split, keep staging'…
harshitsinghbhandari Jun 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Node / Electron
node_modules/
.pnpm/
dist/
out/
build/
Expand All @@ -9,6 +10,7 @@ yarn-debug.log*
yarn-error.log*

# Go
.go/
bin/
*.test
*.out
Expand All @@ -30,6 +32,7 @@ session-events.jsonl.*
.ao/

# Environment
.direnv/
.env
.env.*
!.env.example
Expand Down
2 changes: 1 addition & 1 deletion backend/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ linters:
excludes:
- G104 # unchecked errors — errcheck owns this
- G304 # file inclusion via variable — paths are config/run-file/worktree-derived, not user input
- G703 # path traversal via taint — same rationale as G304: paths are daemon-owned

exclusions:
generated: lax # skip sqlc/codegen ("Code generated ... DO NOT EDIT")
Expand All @@ -107,7 +108,6 @@ linters:

formatters:
enable:
- gofmt
- goimports
settings:
goimports:
Expand Down
134 changes: 134 additions & 0 deletions backend/internal/adapters/agent/agent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package agent

import (
"context"
)

// Agent defines the behavior every CLI coding agent adapter must provide.
type Agent interface {
// GetConfigSpec describes the agent-specific config keys Better-AO can
// expose to users in ~/.better-ao/config.yaml.
GetConfigSpec(ctx context.Context) (ConfigSpec, error)

// GetLaunchCommand builds the command Better-AO should run to start this agent.
GetLaunchCommand(ctx context.Context, cfg LaunchConfig) (cmd []string, err error)

// GetPromptDeliveryStrategy tells Better-AO whether the prompt is included in
// the launch command or must be sent after the agent process starts.
GetPromptDeliveryStrategy(ctx context.Context, cfg LaunchConfig) (PromptDeliveryStrategy, error)

// GetAgentHooks installs or merges Better-AO hooks into the agent's
// native workspace-local hook config. It must preserve user-defined hooks.
GetAgentHooks(ctx context.Context, cfg WorkspaceHookConfig) error

// GetRestoreCommand builds a command that continues an existing native agent
// session. ok=false means no existing native session can be continued.
GetRestoreCommand(ctx context.Context, cfg RestoreConfig) (cmd []string, ok bool, err error)

// SessionInfo reads agent-owned session metadata such as native session id,
// display title, or summary. ok=false means no info is available.
SessionInfo(ctx context.Context, session SessionRef) (info SessionInfo, ok bool, err error)
}

// MetadataKeyAgentSessionID is the SessionRef.Metadata key under which every
// adapter persists the native agent session id captured at launch and reads it
// back during restore. The Better-AO portshim sets it so the underlying
// adapter's GetRestoreCommand sees a unified location regardless of harness.
const MetadataKeyAgentSessionID = "agentSessionId"

// Config contains values loaded from the selected agent's config section.
// Agent adapters own validation for their custom keys.
type Config map[string]any

// ConfigSpec describes the agent-specific config keys AO can expose to users.
type ConfigSpec struct {
Fields []ConfigField
}

// ConfigField describes one user-facing agent config key.
type ConfigField struct {
Key string
Type ConfigFieldType
Description string
Required bool
Default any
Enum []string
}

// ConfigFieldType is the primitive value kind Better-AO expects for a field.
type ConfigFieldType string

// Known ConfigFieldType values.
const (
ConfigFieldString ConfigFieldType = "string"
ConfigFieldBool ConfigFieldType = "bool"
ConfigFieldNumber ConfigFieldType = "number"
ConfigFieldStringList ConfigFieldType = "string_list"
ConfigFieldEnum ConfigFieldType = "enum"
)

// LaunchConfig carries inputs needed to build a new agent launch command.
type LaunchConfig struct {
Config Config
IssueID string
Permissions PermissionMode
Prompt string
SessionID string
SystemPrompt string
SystemPromptFile string
WorkspacePath string
}

// WorkspaceHookConfig carries inputs needed to install workspace-local agent hooks.
type WorkspaceHookConfig struct {
Config Config
DataDir string
SessionID string
WorkspacePath string
}

// RestoreConfig carries inputs needed to continue an existing native agent session.
type RestoreConfig struct {
Config Config
Permissions PermissionMode
Session SessionRef
}

// SessionRef identifies a Better-AO session whose agent-owned metadata may be read.
type SessionRef struct {
ID string
Metadata map[string]string
WorkspacePath string
}

// SessionInfo contains agent-owned session metadata.
type SessionInfo struct {
AgentSessionID string
Metadata map[string]string
Title string
Summary string
}

// PermissionMode controls how much review an agent requires before acting.
type PermissionMode string

// Known PermissionMode values.
//
// PermissionModeDefault is special: adapters emit no flag for it so the agent
// resolves its starting mode from the user's own config (e.g. Claude's TUI
// reading ~/.claude/settings.json defaultMode).
const (
PermissionModeDefault PermissionMode = "default"
PermissionModeAcceptEdits PermissionMode = "accept-edits"
PermissionModeAuto PermissionMode = "auto"
PermissionModeBypassPermissions PermissionMode = "bypass-permissions"
)

// PromptDeliveryStrategy describes how Better-AO should deliver the initial prompt.
type PromptDeliveryStrategy string

// Known PromptDeliveryStrategy values.
const (
PromptDeliveryInCommand PromptDeliveryStrategy = "in_command"
PromptDeliveryAfterStart PromptDeliveryStrategy = "after_start"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "better-ao hooks claude-code session-start",
"timeout": 30
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "better-ao hooks claude-code user-prompt-submit",
"timeout": 30
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "better-ao hooks claude-code stop",
"timeout": 30
}
]
}
]
}
}
Loading
Loading