Skip to content

Commit fe4d4c4

Browse files
committed
Added support for all AI agents + docs.
1 parent 92481f3 commit fe4d4c4

16 files changed

Lines changed: 201 additions & 148 deletions
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
sidebar_label: AI
3+
sidebar_position: 7
4+
---
5+
6+
# AI
7+
8+
**Vortex** provides built-in support for AI coding agents. The integration is
9+
configured through structured markdown files that give agents the context they
10+
need to work effectively within the project.
11+
12+
## How it works
13+
14+
The AI integration follows the same two-tier documentation pattern used
15+
throughout **Vortex**:
16+
17+
- **What** applies to the project is defined in the `docs/` directory. The
18+
agent reads all files in `docs/` to understand project-specific decisions
19+
such as testing conventions, CI configuration, deployment rules, and
20+
release processes.
21+
- **How** to perform operations is sourced from the
22+
https://www.vortextemplate.com/docs (this site). The
23+
`AGENTS.md` file instructs agents to fetch operational guides from the
24+
website and cache them locally in `.data/ai-artifacts/`.
25+
26+
This means AI agents receive the same layered guidance as human developers:
27+
project-level decisions first, then Vortex-level procedures.
28+
29+
## Configuration files
30+
31+
### `AGENTS.md`
32+
33+
The [`AGENTS.md`](https://github.com/drevops/vortex/blob/main/AGENTS.md) file
34+
in the project root is the primary configuration for AI coding agents. It is
35+
an agent-agnostic file that any AI tool can use.
36+
37+
Key sections include:
38+
39+
- **Daily development tasks** — a reference of `ahoy` commands for building,
40+
testing, and managing the local environment.
41+
- **Critical rules** — constraints that agents must always follow (e.g., never
42+
modify `scripts/vortex/`, always export config after admin UI changes).
43+
- **Key directories** — the project's directory layout.
44+
- **Documentation** — instructions for agents to check `docs/` files for
45+
project-specific decisions and to fetch operational documentation from
46+
https://www.vortextemplate.com/docs. Fetched documentation is cached locally so
47+
that agents can reuse it across sessions without repeated requests.
48+
49+
### `CLAUDE.md`
50+
51+
The [`CLAUDE.md`](https://github.com/drevops/vortex/blob/main/CLAUDE.md) file
52+
is automatically loaded by Claude Code at the start of every session. It
53+
references `AGENTS.md` for the full development guide.

.vortex/installer/src/Prompts/Handlers/AiCodeInstructions.php

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,29 @@
44

55
namespace DrevOps\VortexInstaller\Prompts\Handlers;
66

7-
class AiCodeInstructions extends AbstractHandler {
8-
9-
const NONE = 'none';
7+
use DrevOps\VortexInstaller\Utils\File;
108

11-
const CLAUDE = 'claude';
9+
class AiCodeInstructions extends AbstractHandler {
1210

1311
/**
1412
* {@inheritdoc}
1513
*/
1614
public function label(): string {
17-
return 'AI code assistant instructions';
15+
return 'Provide AI agent instructions?';
1816
}
1917

2018
/**
2119
* {@inheritdoc}
2220
*/
2321
public function hint(array $responses): ?string {
24-
return 'Provides AI coding assistants with better context about the project.';
25-
}
26-
27-
/**
28-
* {@inheritdoc}
29-
*/
30-
public function options(array $responses): ?array {
31-
return [
32-
self::CLAUDE => 'Anthropic Claude',
33-
self::NONE => 'None',
34-
];
22+
return 'Provides AI coding agents with better context about the project.';
3523
}
3624

3725
/**
3826
* {@inheritdoc}
3927
*/
4028
public function default(array $responses): null|string|bool|array {
41-
return self::CLAUDE;
29+
return TRUE;
4230
}
4331

4432
/**
@@ -49,21 +37,18 @@ public function discover(): null|string|bool|array {
4937
return NULL;
5038
}
5139

52-
if (is_readable($this->dstDir . '/CLAUDE.md')) {
53-
return self::CLAUDE;
54-
}
55-
56-
return self::NONE;
40+
return File::exists($this->dstDir . '/AGENTS.md') || File::exists($this->dstDir . '/CLAUDE.md');
5741
}
5842

5943
/**
6044
* {@inheritdoc}
6145
*/
6246
public function process(): void {
63-
$v = $this->getResponseAsString();
47+
$v = $this->getResponseAsBool();
6448
$t = $this->tmpDir;
6549

66-
if ($v !== self::CLAUDE) {
50+
if (!$v) {
51+
@unlink($t . '/AGENTS.md');
6752
@unlink($t . '/CLAUDE.md');
6853
}
6954
}

.vortex/installer/src/Prompts/PromptManager.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ public function runPrompts(): void {
205205
->add(fn($r, $pr, $n): bool => confirm(...$this->args(PreserveDocsProject::class)), PreserveDocsProject::id())
206206

207207
->intro('AI')
208-
->add(fn($r, $pr, $n): int|string => select(...$this->args(AiCodeInstructions::class)), AiCodeInstructions::id());
208+
->add(fn($r, $pr, $n): bool => confirm(...$this->args(AiCodeInstructions::class)), AiCodeInstructions::id());
209209

210210
// @formatter:on
211211
// phpcs:enable Generic.Functions.FunctionCallArgumentSpacing.TooMuchSpaceAfterComma
@@ -468,7 +468,7 @@ public function getResponsesSummary(): array {
468468
$values['Preserve project documentation'] = Converter::bool($responses[PreserveDocsProject::id()]);
469469

470470
$values['AI'] = Tui::LIST_SECTION_TITLE;
471-
$values['AI code assistant instructions'] = $responses[AiCodeInstructions::id()];
471+
$values['AI agent instructions'] = Converter::bool($responses[AiCodeInstructions::id()]);
472472

473473
$values['Locations'] = Tui::LIST_SECTION_TITLE;
474474
$values['Current directory'] = $this->config->getRoot();

.vortex/installer/tests/Fixtures/handler_process/ai_instructions_none/-CLAUDE.md renamed to .vortex/installer/tests/Fixtures/handler_process/ai_instructions_disabled/-AGENTS.md

File renamed without changes.

.vortex/installer/tests/Fixtures/handler_process/ai_instructions_disabled/-CLAUDE.md

Whitespace-only changes.

.vortex/installer/tests/Fixtures/handler_process/ai_instructions_none/.ignorecontent renamed to .vortex/installer/tests/Fixtures/handler_process/ai_instructions_disabled/.ignorecontent

File renamed without changes.

.vortex/installer/tests/Functional/Handlers/AiCodeInstructionsHandlerProcessTest.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use DrevOps\VortexInstaller\Prompts\Handlers\AiCodeInstructions;
88
use DrevOps\VortexInstaller\Prompts\PromptManager;
9+
use DrevOps\VortexInstaller\Tests\Functional\FunctionalTestCase;
910
use DrevOps\VortexInstaller\Utils\Env;
1011
use PHPUnit\Framework\Attributes\CoversClass;
1112

@@ -14,12 +15,20 @@ class AiCodeInstructionsHandlerProcessTest extends AbstractHandlerProcessTestCas
1415

1516
public static function dataProviderHandlerProcess(): array {
1617
return [
17-
'ai instructions, claude' => [
18-
static::cw(fn() => Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), AiCodeInstructions::CLAUDE)),
18+
'ai instructions, enabled' => [
19+
static::cw(fn() => Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), Env::TRUE)),
20+
static::cw(function (FunctionalTestCase $test): void {
21+
$test->assertFileExists(static::$sut . '/AGENTS.md');
22+
$test->assertFileExists(static::$sut . '/CLAUDE.md');
23+
}),
1924
],
2025

21-
'ai instructions, none' => [
22-
static::cw(fn() => Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), AiCodeInstructions::NONE)),
26+
'ai instructions, disabled' => [
27+
static::cw(fn() => Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), Env::FALSE)),
28+
static::cw(function (FunctionalTestCase $test): void {
29+
$test->assertFileDoesNotExist(static::$sut . '/AGENTS.md');
30+
$test->assertFileDoesNotExist(static::$sut . '/CLAUDE.md');
31+
}),
2332
],
2433
];
2534
}

.vortex/installer/tests/Functional/Handlers/CiProviderHandlerProcessTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static function dataProviderHandlerProcess(): array {
1919
'ciprovider, gha' => [
2020
static::cw(function (): void {
2121
Env::put(PromptManager::makeEnvName(CiProvider::id()), CiProvider::GITHUB_ACTIONS);
22-
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), AiCodeInstructions::CLAUDE);
22+
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), Env::TRUE);
2323
}),
2424
static::cw(function (FunctionalTestCase $test): void {
2525
$test->assertFileNotContainsString(static::$sut . '/.github/workflows/build-test-deploy.yml', '1.x');
@@ -30,7 +30,7 @@ public static function dataProviderHandlerProcess(): array {
3030
'ciprovider, circleci' => [
3131
static::cw(function (): void {
3232
Env::put(PromptManager::makeEnvName(CiProvider::id()), CiProvider::CIRCLECI);
33-
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), AiCodeInstructions::CLAUDE);
33+
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), Env::TRUE);
3434
}),
3535
static::cw(function (FunctionalTestCase $test): void {
3636
$test->assertFileNotContainsString(static::$sut . '/.circleci/config.yml', '1.x');

.vortex/installer/tests/Functional/Handlers/DatabaseDownloadSourceHandlerProcessTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public static function dataProviderHandlerProcess(): array {
3737
static::cw(function (): void {
3838
Env::put(PromptManager::makeEnvName(DatabaseDownloadSource::id()), DatabaseDownloadSource::CONTAINER_REGISTRY);
3939
Env::put(PromptManager::makeEnvName(DatabaseImage::id()), 'the_empire/star_wars:latest');
40-
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), AiCodeInstructions::CLAUDE);
40+
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), Env::TRUE);
4141
}),
4242
],
4343

.vortex/installer/tests/Functional/Handlers/HostingProviderHandlerProcessTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ public static function dataProviderHandlerProcess(): array {
1919
'hosting, acquia' => [
2020
static::cw(function (): void {
2121
Env::put(PromptManager::makeEnvName(HostingProvider::id()), HostingProvider::ACQUIA);
22-
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), AiCodeInstructions::CLAUDE);
22+
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), Env::TRUE);
2323
}),
2424
],
2525

2626
'hosting, lagoon' => [
2727
static::cw(function (): void {
2828
Env::put(PromptManager::makeEnvName(HostingProvider::id()), HostingProvider::LAGOON);
29-
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), AiCodeInstructions::CLAUDE);
29+
Env::put(PromptManager::makeEnvName(AiCodeInstructions::id()), Env::TRUE);
3030
}),
3131
static::cw(fn(FunctionalTestCase $test) => $test->assertSutNotContains('acquia')),
3232
],

0 commit comments

Comments
 (0)