Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/agents.md
/.agents/
/.context
/.bundle
/pkg
Expand Down
19 changes: 10 additions & 9 deletions context/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,24 @@ bake agent:context:list --gem async
bake agent:context:show --gem async --file thread-safety
```

## Understanding context/ vs .context/
## Understanding context/ vs .agents/context/

**Important distinction:**
- **`context/`** (no dot) = Directory in gems that contains context files to share.
- **`.context/`** (with dot) = Directory in your project where context gets installed.
- **`.agents/context/`** (with dot) = Directory in your project where context gets installed.

### What happens when you install context?

When you run `bake agent:context:install`, the tool:

1. Scans all installed gems for `context/` directories (in the gem's root).
2. Creates a `.context/` directory in your current project.
2. Creates a `.agents/context/` directory in your current project.
3. Copies context files organized by gem name.

For example:
```
your-project/
├── .context/ # ← Installed context (with dot)
├── .agents/context/ # ← Installed context (with dot)
│ ├── async/ # ← From the 'async' gem's context/ directory
│ │ ├── thread-safety.md
│ │ └── performance.md
Expand Down Expand Up @@ -87,9 +87,10 @@ async-gem/

### Key Points for Users

- Run `bake agent:context:install` to copy context to `.context/` (with dot).
- The `.context/` directory is where installed context lives in your project.
- Don't edit files in `.context/` - they get completely replaced when you reinstall.
- Run `bake agent:context:install` to copy context to `.agents/context/` (with dot).
- The `.agents/context/` directory is where installed context lives in your project.
- Ignore the generated `.agents/` directory in version control.
- Don't edit files in `.agents/context/` - they get completely replaced when you reinstall.

## Providing Context (For Gem Authors)

Expand All @@ -109,7 +110,7 @@ your-gem/
└── your-gem.gemspec
```

**Important:** This is different from `.context/` (with dot) which is where context gets installed in user projects.
**Important:** This is different from `.agents/context/` (with dot) which is where context gets installed in user projects.

#### 2. Add context files

Expand Down Expand Up @@ -186,4 +187,4 @@ Before publishing, test your context files:
## Summary

- **`context/`** = source (in gems).
- **`.context/`** = destination (in your project).
- **`.agents/context/`** = destination (in your project).
19 changes: 10 additions & 9 deletions guides/getting-started/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,24 @@ bake agent:context:list --gem async
bake agent:context:show --gem async --file thread-safety
```

## Understanding context/ vs .context/
## Understanding context/ vs .agents/context/

**Important distinction:**
- **`context/`** (no dot) = Directory in gems that contains context files to share.
- **`.context/`** (with dot) = Directory in your project where context gets installed.
- **`.agents/context/`** (with dot) = Directory in your project where context gets installed.

### What happens when you install context?

When you run `bake agent:context:install`, the tool:

1. Scans all installed gems for `context/` directories (in the gem's root).
2. Creates a `.context/` directory in your current project.
2. Creates a `.agents/context/` directory in your current project.
3. Copies context files organized by gem name.

For example:
```
your-project/
├── .context/ # ← Installed context (with dot)
├── .agents/context/ # ← Installed context (with dot)
│ ├── async/ # ← From the 'async' gem's context/ directory
│ │ ├── thread-safety.md
│ │ └── performance.md
Expand Down Expand Up @@ -87,9 +87,10 @@ async-gem/

### Key Points for Users

- Run `bake agent:context:install` to copy context to `.context/` (with dot).
- The `.context/` directory is where installed context lives in your project.
- Don't edit files in `.context/` - they get completely replaced when you reinstall.
- Run `bake agent:context:install` to copy context to `.agents/context/` (with dot).
- The `.agents/context/` directory is where installed context lives in your project.
- Ignore the generated `.agents/` directory in version control.
- Don't edit files in `.agents/context/` - they get completely replaced when you reinstall.

## Providing Context (For Gem Authors)

Expand All @@ -109,7 +110,7 @@ your-gem/
└── your-gem.gemspec
```

**Important:** This is different from `.context/` (with dot) which is where context gets installed in user projects.
**Important:** This is different from `.agents/context/` (with dot) which is where context gets installed in user projects.

#### 2. Add context files

Expand Down Expand Up @@ -186,4 +187,4 @@ Before publishing, test your context files:
## Summary

- **`context/`** = source (in gems).
- **`.context/`** = destination (in your project).
- **`.agents/context/`** = destination (in your project).
1 change: 1 addition & 0 deletions lib/agent/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Copyright, 2025, by Samuel Williams.

require_relative "context/version"
require_relative "context/paths"
require_relative "context/installer"
require_relative "context/index"

Expand Down
17 changes: 12 additions & 5 deletions lib/agent/context/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
# Copyright, 2025, by Shopify Inc.

require_relative "version"
require_relative "paths"
require "fileutils"
require "pathname"
require "yaml"

# @namespace
Expand All @@ -19,12 +21,15 @@ module Context
# agents.md files, update the context section, and generate new files when needed.
class Index
# Initialize a new index instance.
# @parameter context_path [String] The path to the context directory (default: ".context").
def initialize(context_path = ".context")
# @parameter context_path [String] The directory containing installed context.
# @parameter context_link_path [String] The path used for links from `agents.md`.
def initialize(context_path = CONTEXT_PATH, context_link_path: CONTEXT_PATH)
@context_path = context_path
@context_link_path = context_link_path
end

attr :context_path
attr :context_link_path

# Update or create an AGENTS.md file in the project root with context section
# This follows the AGENTS.md specification for agentic coding tools
Expand Down Expand Up @@ -74,7 +79,8 @@ def generate_context_section
# Use files from index if available, otherwise fall back to parsing
if index["files"] && !index["files"].empty?
index["files"].each do |file_info|
sections << "#### [#{file_info['title']}](.context/#{gem_name}/#{file_info['path']})"
link_path = File.join(@context_link_path, gem_name, file_info["path"])
sections << "#### [#{file_info['title']}](#{link_path})"
sections << ""
sections << file_info["description"] if file_info["description"] && !file_info["description"].empty?
sections << ""
Expand All @@ -84,8 +90,9 @@ def generate_context_section
files.each do |file_path|
if File.exist?(file_path)
title, description = extract_content(file_path)
relative_path = file_path.sub("#{@context_path}/", "")
sections << "#### [#{title}](.context/#{relative_path})"
relative_path = Pathname.new(file_path).relative_path_from(Pathname.new(@context_path))
link_path = File.join(@context_link_path, relative_path.to_s)
sections << "#### [#{title}](#{link_path})"
sections << ""
sections << description if description && !description.empty?
sections << ""
Expand Down
9 changes: 6 additions & 3 deletions lib/agent/context/installer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
require "pathname"
require "yaml"

require_relative "paths"

module Agent
module Context
# Installer class for managing context files from Ruby gems.
Expand All @@ -31,11 +33,12 @@ class Installer
# @parameter root [String] The root directory to work from (default: current directory).
# @parameter specifications [Gem::Specification] The gem specifications to search (default: all installed gems).
def initialize(root: Dir.pwd, specifications: ::Gem::Specification)
@root = root
@context_path = ".context"
@root = File.expand_path(root)
@context_path = File.join(@root, CONTEXT_PATH)
@specifications = specifications
end

attr_reader :root
attr_reader :context_path

# Find all gems that have a context directory
Expand All @@ -44,7 +47,7 @@ def find_gems_with_context(skip_local: true)

@specifications.each do |spec|
# Skip gems loaded from current working directory if requested:
next if skip_local && spec.full_gem_path == @root
next if skip_local && File.expand_path(spec.full_gem_path) == @root

context_path = File.join(spec.full_gem_path, "context")
if Dir.exist?(context_path)
Expand Down
13 changes: 13 additions & 0 deletions lib/agent/context/paths.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2025, by Shopify Inc.
# Copyright, 2025-2026, by Samuel Williams.

# @namespace
module Agent
# @namespace
module Context
CONTEXT_PATH = File.join(".agents", "context")
end
end
6 changes: 3 additions & 3 deletions post.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

**Claude:** "So how does this work in practice?"

**Ruby:** "Let me show you! When a developer runs `bake agent:context:install`, it scans all my installed gems for `context/` directories, copies the files to a `.context/` folder in their project, and generates an `agents.md` file that gives you a comprehensive overview."
**Ruby:** "Let me show you! When a developer runs `bake agent:context:install`, it scans all my installed gems for `context/` directories, copies the files to a `.agents/context/` folder in their project, and generates an `agents.md` file that gives you a comprehensive overview."

**Claude:** "That sounds perfect! What does this `agents.md` file look like?"

Expand All @@ -45,15 +45,15 @@ Context files from installed gems providing documentation and guidance for AI ag

Code analysis for documentation generation.

#### [Getting Started with Decode](.context/decode/getting-started.md)
#### [Getting Started with Decode](.agents/context/decode/getting-started.md)

The Decode gem provides programmatic access to Ruby code structure...

### sus

A fast and scalable test runner.

#### [Using Sus Testing Framework](.context/sus/usage.md)
#### [Using Sus Testing Framework](.agents/context/sus/usage.md)

Sus is a modern Ruby testing framework...
```
Expand Down
12 changes: 6 additions & 6 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Provides tools for installing and managing context files from Ruby gems for AI a

This gem allows you to install and manage context files from other gems. Gems can provide context files in a `context/` directory in their root, which can contain documentation, configuration examples, migration guides, and other contextual information for AI agents.

When you install context from gems, they are placed in the `.context/` directory and an `agents.md` file is generated or updated to provide a comprehensive overview for AI agents.
When you install context from gems, they are placed in the `.agents/context/` directory and an `agents.md` file is generated or updated to provide a comprehensive overview for AI agents.

## Quick Start

Expand All @@ -22,7 +22,7 @@ $ bake agent:context:install
This workflow:

- Adds the `agent-context` gem to your project.
- Installs context files from all gems into `.context/`.
- Installs context files from all gems into `.agents/context/`.
- Generates or updates `agents.md` with a comprehensive overview.
- Follows the <https://agents.md> specification for agentic coding tools.

Expand All @@ -32,7 +32,7 @@ This gem provides its own context files in the `context/` directory, including:

- `usage.md` - Comprehensive guide for using and providing context files.

When you install context from other gems, they will be placed in the `.context/` directory and referenced in `agents.md`.
When you install context from other gems, they will be placed in the `.agents/context/` directory and referenced in `agents.md`.

## Usage

Expand Down Expand Up @@ -88,11 +88,11 @@ $ bake agent:context:show --gem async --file thread-safety

## Version Control

Both `.context/` and `agents.md` should be committed to git:
The `.agents/` directory contains generated files and should be excluded from version control. The generated `agents.md` index should be committed:

- `agents.md` is user-facing documentation that should be versioned.
- `.context/` files are referenced by `agents.md` and needed for AI agents to function properly.
- This ensures AI agents in CI have access to the full context.
- `.agents/context/` can be restored by running `bake agent:context:install`.
- Ignoring the entire `.agents/` directory covers other generated agent resources too.

## Providing Context in Your Gem

Expand Down
18 changes: 9 additions & 9 deletions specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ A **Context Provider** is any software package, library, or module that includes

A **Context Consumer** is any project or tool that utilizes contextual information from its dependencies. Context consumers:

- Install context from their dependencies into a `.context/` directory.
- Install context from their dependencies into a `.agents/context/` directory.
- Use tools to discover and access available context.
- Apply context based on file patterns and metadata.

Expand Down Expand Up @@ -75,20 +75,20 @@ package-root/
└── package.json
```

### 3.2 Consumer Directory: `.context/`
### 3.2 Consumer Directory: `.agents/context/`

Context consumers SHOULD create a `.context/` directory in their project root to store installed context. This directory:
Context consumers SHOULD create a `.agents/context/` directory in their project root to store installed context. This directory:

- **Location**: Must be at the project root (typically where package manifests are located).
- **Purpose**: Contains context files copied from dependencies.
- **Organization**: Must organize context by package name in subdirectories.
- **Exclusion**: SHOULD be excluded from version control (e.g., in `.gitignore`).
- **Exclusion**: The generated `.agents/` directory SHOULD be excluded from version control (e.g., in `.gitignore`).
- **Transient Nature**: Should contain only reproducible content that can be regenerated from installed packages and MUST NOT contain unique or modified files.

Example structure:
```
project-root/
├── .context/
├── .agents/context/
│ ├── package-a/
│ │ ├── getting-started.md
│ │ └── configuration.md
Expand All @@ -100,9 +100,9 @@ project-root/

### 3.3 Directory Separation Rationale

The separation between `context/` and `.context/` serves several purposes:
The separation between `context/` and `.agents/context/` serves several purposes:

- **Ownership**: `context/` is controlled by the project itself, `.context/` contains external dependencies.
- **Ownership**: `context/` is controlled by the project itself, `.agents/context/` contains external dependencies.
- **Isolation**: Prevents conflicts between different packages' context files.
- **Discoverability**: Makes it easy to find context for specific packages.
- **Maintenance**: Allows independent management of provided vs. consumed context.
Expand Down Expand Up @@ -170,7 +170,7 @@ Context installation MUST follow these principles:

```
FOR each package with context:
CREATE directory .context/package-name/
COPY all files recursively from package/context/ to .context/package-name/
CREATE directory .agents/context/package-name/
COPY all files recursively from package/context/ to .agents/context/package-name/
END
```
10 changes: 5 additions & 5 deletions test/agent/context/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

with "AGENT.md functionality" do
let(:temporary_directory) {Dir.mktmpdir}
let(:context_path) {File.join(temporary_directory, ".context")}
let(:context_path) {File.join(temporary_directory, ".agents", "context")}
let(:agent_md_path) {File.join(temporary_directory, "agent.md")}

def around
Expand Down Expand Up @@ -128,7 +128,7 @@ def around
expect(content).to be(:include?, "# Agent")
expect(content).to be(:include?, "## Context")
expect(content).to be(:include?, "### example_gem")
expect(content).to be(:include?, "#### [Example Gem](.context/example_gem/README.md)")
expect(content).to be(:include?, "#### [Example Gem](.agents/context/example_gem/README.md)")
expect(content).to be(:include?, "This is an example gem that provides context for AI agents")
end

Expand Down Expand Up @@ -159,7 +159,7 @@ def around
content = File.read(agent_md_path)
expect(content).to be(:include?, "### example_gem")
expect(content).to be(:include?, "A test gem with custom index")
expect(content).to be(:include?, "#### [Getting Started Guide](.context/example_gem/getting-started.md)")
expect(content).to be(:include?, "#### [Getting Started Guide](.agents/context/example_gem/getting-started.md)")
expect(content).to be(:include?, "Custom description from index")
end

Expand Down Expand Up @@ -198,7 +198,7 @@ def around

with "title and description extraction" do
let(:temporary_directory) {Dir.mktmpdir}
let(:context_path) {File.join(temporary_directory, ".context")}
let(:context_path) {File.join(temporary_directory, ".agents", "context")}

def around
FileUtils.mkdir_p(context_path)
Expand Down Expand Up @@ -290,7 +290,7 @@ def around

with "index.yaml handling" do
let(:temporary_directory) {Dir.mktmpdir}
let(:context_path) {File.join(temporary_directory, ".context")}
let(:context_path) {File.join(temporary_directory, ".agents", "context")}

def around
FileUtils.mkdir_p(context_path)
Expand Down
Loading
Loading