AI Assist Kit follows the adapter pattern with canonical types at the core and tool-specific adapters at the edges.
┌─────────────────────────────────────────────────────────────────┐
│ aiassistkit │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ plugins │ │commands │ │ skills │ │ agents │ NEW │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ ┌────┴────────────┴────────────┴────────────┴────┐ │
│ │ core/ │ │
│ │ Plugin, Command, Skill, Agent canonical types │ │
│ └────┬────────────┬────────────┬────────────┬────┘ │
│ │ │ │ │ │
│ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │
│ │ claude/ │ │ gemini/ │ │ codex/ │ │ cursor/ │ Adapters │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ mcp │ │ hooks │ │ context │ EXISTING │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────────┘
aiassistkit/
├── aiassistkit.go # Umbrella package, version info
├── go.mod
│
├── plugins/ # NEW: Plugin/extension manifests
│ ├── plugins.go # Package umbrella with re-exports
│ ├── core/
│ │ ├── plugin.go # Plugin struct
│ │ ├── adapter.go # Adapter interface & registry
│ │ └── errors.go # Error types
│ ├── claude/
│ │ ├── adapter.go # .claude-plugin/plugin.json
│ │ └── config.go # Claude-specific types
│ ├── gemini/
│ │ ├── adapter.go # gemini-extension.json
│ │ └── config.go # Gemini-specific types
│ └── schema/
│ └── plugin.schema.json # JSON Schema
│
├── commands/ # NEW: Commands/prompts
│ ├── commands.go # Package umbrella
│ ├── core/
│ │ ├── command.go # Command struct
│ │ ├── adapter.go # Adapter interface & registry
│ │ └── errors.go # Error types
│ ├── claude/
│ │ └── adapter.go # commands/*.md (Markdown + YAML)
│ ├── gemini/
│ │ └── adapter.go # commands/*.toml (TOML)
│ ├── codex/
│ │ └── adapter.go # prompts/*.md (Markdown + YAML)
│ └── schema/
│ └── command.schema.json # JSON Schema
│
├── skills/ # NEW: Skill definitions
│ ├── skills.go # Package umbrella
│ ├── core/
│ │ ├── skill.go # Skill struct
│ │ ├── adapter.go # Adapter interface & registry
│ │ └── errors.go # Error types
│ ├── claude/
│ │ └── adapter.go # skills/*/SKILL.md
│ ├── codex/
│ │ └── adapter.go # skills/*/SKILL.md
│ └── schema/
│ └── skill.schema.json # JSON Schema
│
├── agents/ # NEW: Agent definitions
│ ├── agents.go # Package umbrella
│ ├── core/
│ │ ├── agent.go # Agent struct
│ │ ├── adapter.go # Adapter interface & registry
│ │ └── errors.go # Error types
│ ├── claude/
│ │ └── adapter.go # agents/*.md
│ └── schema/
│ └── agent.schema.json # JSON Schema
│
├── mcp/ # EXISTING: MCP configurations
├── hooks/ # EXISTING: Lifecycle hooks
├── context/ # EXISTING: Project context
│
└── cmd/
└── aiassistkit/ # CLI tool
└── main.go
// Plugin represents a canonical plugin/extension definition
type Plugin struct {
// Metadata
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
Author string `json:"author,omitempty"`
License string `json:"license,omitempty"`
Repository string `json:"repository,omitempty"`
Homepage string `json:"homepage,omitempty"`
// Components
Commands []string `json:"commands,omitempty"` // Paths to command specs
Skills []string `json:"skills,omitempty"` // Paths to skill specs
Agents []string `json:"agents,omitempty"` // Paths to agent specs
Hooks string `json:"hooks,omitempty"` // Path to hooks spec
// Dependencies
Dependencies []Dependency `json:"dependencies,omitempty"`
// MCP Servers (for Gemini)
MCPServers map[string]MCPServer `json:"mcp_servers,omitempty"`
}
type Dependency struct {
Name string `json:"name"`
Command string `json:"command,omitempty"` // CLI command to check
Optional bool `json:"optional,omitempty"`
}
type MCPServer struct {
Command string `json:"command"`
Args []string `json:"args,omitempty"`
Env map[string]string `json:"env,omitempty"`
}// Command represents a canonical command/prompt definition
type Command struct {
// Metadata
Name string `json:"name"`
Description string `json:"description"`
// Arguments
Arguments []Argument `json:"arguments,omitempty"`
// Content
Instructions string `json:"instructions"` // The prompt/instructions
// Process steps (for documentation)
Process []string `json:"process,omitempty"`
// Dependencies
Dependencies []string `json:"dependencies,omitempty"`
}
type Argument struct {
Name string `json:"name"`
Type string `json:"type"` // string, number, boolean
Required bool `json:"required,omitempty"`
Default string `json:"default,omitempty"`
Pattern string `json:"pattern,omitempty"` // Regex validation
Hint string `json:"hint,omitempty"` // User hint
Description string `json:"description,omitempty"`
}// Skill represents a canonical skill definition
type Skill struct {
// Metadata
Name string `json:"name"`
Description string `json:"description"`
// Content
Instructions string `json:"instructions"` // The skill instructions
// Resources
Scripts []string `json:"scripts,omitempty"` // Script files
References []string `json:"references,omitempty"` // Reference docs
Assets []string `json:"assets,omitempty"` // Template files
// Invocation
Triggers []string `json:"triggers,omitempty"` // Keywords that invoke
}// Agent represents a canonical agent definition
type Agent struct {
// Metadata
Name string `json:"name"`
Description string `json:"description"`
// Configuration
Model string `json:"model,omitempty"` // sonnet, opus, haiku
Tools []string `json:"tools,omitempty"` // Allowed tools
Skills []string `json:"skills,omitempty"` // Skills to load
// Content
Instructions string `json:"instructions"` // Agent instructions
// Behavior
MaxTurns int `json:"max_turns,omitempty"`
AllowParallel bool `json:"allow_parallel,omitempty"`
}Each package follows the same adapter pattern:
// Adapter converts between canonical and tool-specific formats
type Adapter interface {
// Name returns the adapter identifier (e.g., "claude", "gemini")
Name() string
// DefaultPaths returns default file paths for this tool
DefaultPaths() []string
// Parse converts tool-specific bytes to canonical type
Parse(data []byte) (*Config, error)
// Marshal converts canonical type to tool-specific bytes
Marshal(cfg *Config) ([]byte, error)
// ReadFile reads from path and returns canonical type
ReadFile(path string) (*Config, error)
// WriteFile writes canonical type to path
WriteFile(cfg *Config, path string) error
}Output: commands/{name}.md
---
description: Execute full release workflow
---
# Release
Execute a full release workflow with validation, changelog generation, and git tagging.
## Usage
/release-agent:release
## Arguments
- **version** (required): Semantic version (e.g., v1.2.3)
## Process
1. Run validation checks
2. Generate changelog
3. Create and push git tag
Output: commands/{group}/{name}.toml
[command]
name = "release"
description = "Execute full release workflow"
[[arguments]]
name = "version"
type = "string"
required = true
hint = "Semantic version (e.g., v1.2.3)"
[content]
instructions = """
Execute a full release workflow with validation, changelog generation, and git tagging.
Process:
1. Run validation checks
2. Generate changelog
3. Create and push git tag
"""Output: prompts/{name}.md
---
description: Execute full release workflow
argument-hint: VERSION=<semver>
---
Execute a full release workflow with validation, changelog generation, and git tagging.
Arguments:
- $VERSION: Semantic version (e.g., v1.2.3)
Process:
1. Run validation checks
2. Generate changelog
3. Create and push git tag{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/plexusone/assistantkit/plugins/schema/plugin.schema.json",
"title": "AI Assist Kit Plugin",
"description": "Canonical plugin/extension definition",
"type": "object",
"required": ["name", "version", "description"],
"properties": {
"name": {
"type": "string",
"pattern": "^[a-z][a-z0-9-]*$",
"description": "Plugin identifier (lowercase, hyphens)"
},
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+",
"description": "Semantic version"
},
"description": {
"type": "string",
"maxLength": 200
},
"commands": {
"type": "array",
"items": {"type": "string"}
},
"skills": {
"type": "array",
"items": {"type": "string"}
},
"agents": {
"type": "array",
"items": {"type": "string"}
},
"dependencies": {
"type": "array",
"items": {
"type": "object",
"required": ["name"],
"properties": {
"name": {"type": "string"},
"command": {"type": "string"},
"optional": {"type": "boolean"}
}
}
}
}
}Each package uses a registry for adapter management:
var (
mu sync.RWMutex
adapters = make(map[string]Adapter)
)
// Register adds an adapter to the registry
func Register(adapter Adapter) {
mu.Lock()
defer mu.Unlock()
adapters[adapter.Name()] = adapter
}
// GetAdapter returns an adapter by name
func GetAdapter(name string) (Adapter, bool) {
mu.RLock()
defer mu.RUnlock()
adapter, ok := adapters[name]
return adapter, ok
}
// AdapterNames returns all registered adapter names
func AdapterNames() []string {
mu.RLock()
defer mu.RUnlock()
names := make([]string, 0, len(adapters))
for name := range adapters {
names = append(names, name)
}
sort.Strings(names)
return names
}Adapters self-register via init():
func init() {
core.Register(&claudeAdapter{})
}Custom error types with unwrapping:
type ParseError struct {
Format string
Path string
Err error
}
func (e *ParseError) Error() string {
return fmt.Sprintf("parse %s (%s): %v", e.Format, e.Path, e.Err)
}
func (e *ParseError) Unwrap() error {
return e.Err
}Secure defaults for generated files:
const DefaultFileMode fs.FileMode = 0600 // User read/write only
const DefaultDirMode fs.FileMode = 0700 // User read/write/execute only- Unit Tests: Each adapter has round-trip tests
- Integration Tests: Cross-adapter conversion tests
- Schema Validation: JSON Schema validation tests
- Golden Files: Expected output comparisons
- Go 1.23+ (for modern features)
github.com/pelletier/go-toml/v2(Codex/Gemini TOML)- No other external dependencies (stdlib only where possible)
- Lazy adapter loading via init()
- Minimal memory allocation in hot paths
- Streaming for large file operations
- No code execution from parsed configs
- Path traversal prevention
- Secure file permissions by default
- No network operations in core library