Skip to main content
OpenGAP defines a canonical directory structure for AI agent repositories. Every OpenGAP-compliant runtime discovers agent components by following this layout — no separate registry, no config file that lists files by path.

Full layout

my-agent/                   ← agent root (contains agent.yaml)

├── agent.yaml              ← REQUIRED: agent manifest

├── skills/                 ← OPTIONAL: skill modules
│   ├── skill_one.py        ← single-file skill
│   ├── skill_two.py
│   └── complex_skill/      ← package skill
│       ├── __init__.py     ← must export the @skill-decorated function
│       └── helpers.py

├── hooks/                  ← OPTIONAL: lifecycle hooks
│   ├── before_run.py
│   ├── after_run.py
│   └── on_error.py

├── flows/                  ← OPTIONAL: SkillsFlow definitions
│   ├── research.yaml
│   └── report.yaml

├── memory/                 ← OPTIONAL: memory backend config
│   └── config.yaml

├── plugins/                ← OPTIONAL: runtime plugins
│   └── my_plugin.py

├── prompts/                ← OPTIONAL: prompt templates
│   └── system.txt

└── tests/                  ← OPTIONAL: skill and flow tests
    ├── test_skill_one.py
    └── test_flows.py

Directory semantics

agent.yaml (required)

The agent manifest. Its presence in a directory marks that directory as an OpenGAP agent root. A runtime starts by reading this file. See Agent Manifest for the full schema.

skills/

Each .py file (or Python package) in skills/ that exports a @skill-decorated function is loaded as a skill. The runtime loads all skills before starting the agent loop. Subdirectories are treated as package skills — the runtime imports the package and looks for @skill-decorated functions in __init__.py. Files matching the exclude glob in agent.yaml are ignored.

hooks/

Each .py file in hooks/ that exports hook-decorated functions is loaded. Hook discovery is automatic — the runtime looks for functions decorated with @hooks.before_run, @hooks.after_run, etc. File names do not matter for hook loading. Use descriptive names (audit.py, validation.py) for maintainability.

flows/

Each .yaml file in flows/ is a SkillsFlow definition. Flows are loaded and exposed to the agent as skills unless expose_as_skill: false is set in the flow file.

memory/config.yaml

An optional override for the memory configuration. If present, its settings merge with (and take precedence over) the memory: section in agent.yaml.
# memory/config.yaml
provider: local
max_history: 30

plugins/

Each .py file in plugins/ that defines a class inheriting from a GitAgent plugin base class is loaded as a plugin.

prompts/

Store prompt templates here for use in system prompts or skill implementations. Reference them from agent.yaml:
system_prompt_file: prompts/system.txt

tests/

Tests for skills and flows. The runtime’s test runner (gitagent test) discovers and runs any file matching test_*.py in this directory.

Multiple agents in a monorepo

A repository can contain multiple agents:
monorepo/
├── agents/
│   ├── researcher/
│   │   ├── agent.yaml
│   │   └── skills/
│   └── writer/
│       ├── agent.yaml
│       └── skills/
├── shared/
│   └── skills/         ← shared across agents
└── README.md
In agent.yaml, reference shared skills:
skills:
  path:
    - skills/
    - ../../shared/skills/
The agent root is the directory containing agent.yaml. All relative paths in agent.yaml are relative to the agent root.

Non-Python runtimes

While GitAgent uses Python @skill-decorated functions, the OpenGAP spec allows skill implementations in any language. A non-Python runtime implements the same discovery convention but can load skills from different file types. The spec requires:
  • agent.yaml at the root (required for any runtime)
  • Skills in skills/ (implementation language is runtime-specific)
  • Hooks in hooks/ (implementation language is runtime-specific)
The manifest declares the expected runtime if the agent requires a specific one:
runtime:
  name: gitagent          # optional: hint to tooling
  min_version: "0.7"

Path configuration overrides

All directory paths can be overridden in agent.yaml:
skills:
  path: src/agent/skills/   # non-standard location

hooks:
  path: src/agent/hooks/

flows:
  path: src/agent/flows/
This allows OpenGAP agents to live inside larger project structures where a top-level skills/ directory isn’t appropriate.