Skip to content
Open
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
3 changes: 3 additions & 0 deletions .trellis/scripts/common/active_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@
# platform after the directory it was installed in reports "factory". Its
# sibling hooks report "droid". One runtime filename either way.
"factory": "droid",
# Antigravity's config directories are `.agent/` and `.agents/`.
"agent": "antigravity",
"agents": "antigravity",
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"file": ".trellis/spec/cli/backend/index.md", "reason": "Validate platform registry completeness and template copy manifest sync"}
{"file": ".trellis/spec/cli/unit-test/index.md", "reason": "Validate test coverage for platform hook generators and integration runners"}
44 changes: 44 additions & 0 deletions .trellis/tasks/archive/2026-09/09-03-antigravity-hooks/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Design: Antigravity Lifecycle Hook Integration

## Architecture Overview

```text
Antigravity Session Lifecycle
├── PreInvocation
│ └── sh -c "python3 hooks/inject-workflow-state.py" (cwd: <repo>/.agent)
│ ├── Resolves repo root (walk up from cwd)
│ ├── Reads active task state / workflow phase
│ └── Returns: {"injectSteps": [{"ephemeralMessage": "<workflow-state>..."}]}
└── PreToolUse (matcher: "run_command")
└── sh -c "python3 hooks/inject-shell-session-context.py" (cwd: <repo>/.agent)
├── Inspects toolCall.args.CommandLine
├── Extracts task.py subcommands
├── Writes short-lived shell ticket in .trellis/.runtime/shell-tickets/
└── Returns: {"decision": "allow"}
```

## Key Design Decisions

### 1. Working Directory (`cwd`) Contract
In Antigravity, hooks defined in `.agent/hooks.json` execute with their working directory set to **the directory containing `hooks.json`** (i.e. `<workspace>/.agent/`).
- Setting command to `python3 .agent/hooks/...` causes a double `.agent/.agent/` path resolution failure (`[Errno 2] No such file or directory`).
- Commands are configured as `{{PYTHON_CMD}} hooks/inject-workflow-state.py` and `{{PYTHON_CMD}} hooks/inject-shell-session-context.py`, making them portable and correctly resolved relative to `.agent/`.

### 2. Platform Detection & Host Directory Resolution
When the hook command is executed via `python3 hooks/...`, `sys.argv[0]` contains only the relative path `hooks/...` without `.agent`. Using `Path(sys.argv[0]).resolve().parts` resolves the absolute path, ensuring `.agent` is always identified and mapped to the `antigravity` host identifier.

### 3. Ephemeral Workflow Breadcrumbs
Antigravity's `PreInvocation` hook allows injecting ephemeral context into the model's turn via:
```json
{
"injectSteps": [
{
"ephemeralMessage": "<workflow-state>\nStatus: no_task\n...\n</workflow-state>"
}
]
}
```
This keeps the conversational history clean while ensuring the active task, workflow rules, and guidance are consistently available to the model.

### 4. Shell Ticket Bridge
When Antigravity runs tools via `run_command`, `PreToolUse` passes `{ "toolCall": { "name": "run_command", "args": { "CommandLine": "..." } } }`. The hook writes a shell ticket keyed to `antigravity_<conversation_id>`, allowing subsequent `task.py start/current/finish` commands to seamlessly inherit the session identity.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{"file": ".trellis/spec/cli/backend/index.md", "reason": "CLI template generation, platform configuration registry, and hook installation guidelines"}
{"file": ".trellis/spec/cli/unit-test/index.md", "reason": "Vitest testing conventions, subprocess execution, and cross-platform python detection"}
{"file": ".trellis/spec/guides/cross-layer-thinking-guide.md", "reason": "Cross-layer contract consistency for hook payloads and lifecycle state"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Implementation Plan: Antigravity Lifecycle Hook Integration

## Completed Steps

1. **AI Tools Type Definition**:
- Added `hasPythonHooks: true` and `hasHooks: true` to `AI_TOOLS.antigravity` in `packages/cli/src/types/ai-tools.ts`.
- Added `.agent/hooks` and `.agent/hooks.json` to `extraManagedPaths`.

2. **Template Creation**:
- Created `packages/cli/src/templates/antigravity/hooks.json` with `PreInvocation` and `PreToolUse` events.
- Configured `packages/cli/src/templates/antigravity/index.ts` to export template definitions.

3. **Hook Script Adaptation**:
- Updated `inject-workflow-state.py` to detect `antigravity` and format output as `{"injectSteps": [{"ephemeralMessage": ...}]}`.
- Updated `inject-shell-session-context.py` to extract commands from `toolCall.args.CommandLine` and return `{"decision": "allow"}`.
- Switched to `Path(sys.argv[0]).resolve().parts` for robust platform detection.

4. **Task Context Resolver**:
- Added `"agent": "antigravity"` and `"agents": "antigravity"` to platform indicators in `packages/cli/src/templates/trellis/scripts/common/active_task.py`.

5. **Integration Testing**:
- Created `packages/cli/test/scripts/inject-workflow-state-antigravity.integration.test.ts`.
- Dynamically detected Python command via `getPythonCommandForPlatform()`.
- Verified both `PreInvocation` and `PreToolUse` hooks in simulated Antigravity runtime environment.

6. **Review Feedback Hardening**:
- Addressed CodeRabbit review comments on PR #600: confirmed relative `hooks/` path correctness and verified Python command detection.
42 changes: 42 additions & 0 deletions .trellis/tasks/archive/2026-09/09-03-antigravity-hooks/prd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Support Antigravity lifecycle hooks in Trellis CLI

## Goal

Enable full Trellis lifecycle hook integration for Antigravity (Google DeepMind agentic coding assistant), providing per-turn workflow state injection (`PreInvocation`) and shell session ticket bridging for command authorization (`PreToolUse`).

## Background & Context

Antigravity operates with a customization system under `.agent/` (or `.agents/`), configuring event hooks via `.agent/hooks.json`. Prior to this task, Trellis supported Antigravity workflows (`.agent/workflows/`) and skills (`.agent/skills/`), but lacked lifecycle hook automation. Consequently, Antigravity sessions could not automatically observe `<workflow-state>` breadcrumbs or bridge active session context into shell-invoked Trellis scripts (`task.py`).

## Requirements

1. **Platform Capability Declaration**:
- Mark Antigravity with `hasPythonHooks: true` and `hasHooks: true` in `packages/cli/src/types/ai-tools.ts`.
- Register `.agent/hooks` directory and `.agent/hooks.json` in `extraManagedPaths`.

2. **Template & Configuration**:
- Provide `packages/cli/src/templates/antigravity/hooks.json` mapping `PreInvocation` and `PreToolUse` (for `run_command`).
- Use relative `hooks/...` paths matching Antigravity's runtime working directory contract (where `cwd` is the directory containing `hooks.json`).

3. **Hook Script Adaptation**:
- Update `inject-workflow-state.py` to recognize Antigravity and emit the native `PreInvocation` response envelope: `{"injectSteps": [{"ephemeralMessage": "..."}]}`.
- Update `inject-shell-session-context.py` to parse Antigravity `toolCall.args.CommandLine` and emit `{"decision": "allow"}` with temporary shell ticket generation.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- Robust host detection using `Path(sys.argv[0]).resolve().parts` to reliably locate `.agent` regardless of invocation cwd.

4. **Active Task Resolver**:
- Update `common/active_task.py` to map `.agent` and `.agents` directory indicators to the `antigravity` platform identifier.

5. **Testing & Validation**:
- Add unit tests for platform configuration and template collection.
- Add end-to-end integration tests in `inject-workflow-state-antigravity.integration.test.ts` executing against the generated `.agent/` layout with dynamic Python interpreter resolution.
- Ensure all 372 core tests and 1900 CLI tests pass without regression.

## Acceptance Criteria

- [x] `collectAntigravityTemplates` returns `.agent/hooks.json` and `.agent/hooks/*.py`.
- [x] Hook commands in `hooks.json` execute cleanly with relative `hooks/...` paths.
- [x] `inject-workflow-state.py` injects `<workflow-state>` breadcrumb into Antigravity input.
- [x] `inject-shell-session-context.py` generates `.trellis/.runtime/shell-tickets/` and returns `{"decision": "allow"}`.
- [x] Python command resolution uses `getPythonCommandForPlatform()` in integration tests.
- [x] All 1900 CLI regression tests pass.
- [x] Upstream issue #599 and PR #600 linked and documented.
37 changes: 37 additions & 0 deletions .trellis/tasks/archive/2026-09/09-03-antigravity-hooks/task.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"id": "antigravity-hooks",
"name": "antigravity-hooks",
"title": "Support Antigravity lifecycle hooks in Trellis CLI",
"description": "Add hooks.json lifecycle hooks and session context injection for Antigravity",
"status": "completed",
"dev_type": "feat",
"scope": "cli",
"package": "cli",
"priority": "P1",
"creator": "alan",
"assignee": "alan",
"createdAt": "2026-09-03",
"completedAt": "2026-09-03",
"branch": "feat/antigravity-hooks",
"base_branch": "main",
"worktree_path": null,
"commit": "9c011a9a",
"pr_url": "https://github.com/mindfold-ai/Trellis/pull/600",
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [
"packages/cli/src/types/ai-tools.ts",
"packages/cli/src/templates/antigravity/hooks.json",
"packages/cli/src/templates/antigravity/index.ts",
"packages/cli/src/templates/shared-hooks/inject-workflow-state.py",
"packages/cli/src/templates/shared-hooks/inject-shell-session-context.py",
"packages/cli/src/templates/trellis/scripts/common/active_task.py",
"packages/cli/test/scripts/inject-workflow-state-antigravity.integration.test.ts"
],
"notes": "Added Antigravity lifecycle hooks support, resolving #599 and PR #600.",
"meta": {
"issue": "599",
"pr": "https://github.com/mindfold-ai/Trellis/pull/600"
}
}
43 changes: 43 additions & 0 deletions .trellis/workspace/alan/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Workspace Index - alan

> Journal tracking for AI development sessions.

---

## Current Status

<!-- @@@auto:current-status -->
- **Active File**: `journal-1.md`
- **Total Sessions**: 3
- **Last Active**: 2026-09-03
<!-- @@@/auto:current-status -->

---

## Active Documents

<!-- @@@auto:active-documents -->
| File | Lines | Status |
|------|-------|--------|
| `journal-1.md` | ~85 | Active |
<!-- @@@/auto:active-documents -->

---

## Session History

<!-- @@@auto:session-history -->
| # | Date | Title | Commits | Branch |
|---|------|-------|---------|--------|
| 1 | 2026-09-03 | feat(antigravity): 支持 hooks.json 生命周期钩子与会话状态注入 | `cf6663d3` | `feat/antigravity-hooks` |
| 2 | 2026-09-03 | fix(antigravity): 修正 hook 执行相对路径与宿主目录解析 | `d64de828` | `feat/antigravity-hooks` |
| 3 | 2026-09-03 | test(antigravity): 在集成测试中复用动态探测的 Python 解释器 | `9c011a9a` | `feat/antigravity-hooks` |
<!-- @@@/auto:session-history -->

---

## Notes

- Sessions are appended to journal files
- New journal file created when current exceeds 2000 lines
- Use `add_session.py` to record sessions
110 changes: 110 additions & 0 deletions .trellis/workspace/alan/journal-1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Journal - alan (Part 1)

> AI development session journal
> Started: 2026-09-03

---

## Session 1: feat(antigravity): 支持 hooks.json 生命周期钩子与会话状态注入

**Date**: 2026-09-03
**Task**: Support Antigravity lifecycle hooks in Trellis CLI
**Package**: cli
**Branch**: `feat/antigravity-hooks`

### Summary

为 Antigravity 平台添加 lifecycle hooks 支持,包含每轮会话状态注入和 shell 会话桥接。

### Main Changes

- 在 `AI_TOOLS.antigravity` 中开启 `hasPythonHooks: true` 与 `hasHooks: true`,并将 `.agent/hooks*` 加入 `extraManagedPaths`
- 添加 `packages/cli/src/templates/antigravity/hooks.json` 模板与平台配置器
- 适配 `inject-workflow-state.py` 生成 Antigravity 原生 `injectSteps` 临时消息
- 适配 `inject-shell-session-context.py` 处理 `toolCall.args.CommandLine` 并生成短效 shell ticket
- 在 `common/active_task.py` 中增加 `agent`/`agents` 映射至 `antigravity`

### Git Commits

| Hash | Message |
|------|---------|
| `cf6663d3` | feat(antigravity): 支持 hooks.json 生命周期钩子与会话状态注入 (#599) |

### Testing

- [OK] 372 core 测试通过
- [OK] 1900 CLI 测试通过

### Status

[OK] **Completed**

---

## Session 2: fix(antigravity): 修正 hook 执行相对路径与宿主目录解析

**Date**: 2026-09-03
**Task**: Support Antigravity lifecycle hooks in Trellis CLI
**Package**: cli
**Branch**: `feat/antigravity-hooks`

### Summary

修正 Antigravity hooks 执行时的相对路径错误与宿主目录解析。

### Main Changes

- 将 `hooks.json` 中的命令路径从 `.agent/hooks/...` 改为相对路径 `hooks/...`,匹配 Antigravity 以 `hooks.json` 所在目录作为 cwd 的机制
- 脚本改用 `Path(sys.argv[0]).resolve().parts` 稳健识别宿主 `.agent` 目录
- 更新集成测试匹配真实 Antigravity 执行工作目录

### Git Commits

| Hash | Message |
|------|---------|
| `d64de828` | fix(antigravity): 修正 hook 执行相对路径与宿主目录解析 (#599) |

### Testing

- [OK] 集成测试覆盖真实 cwd 模拟通过
- [OK] 1900 CLI 测试通过

### Status

[OK] **Completed**

---

## Session 3: test(antigravity): 在集成测试中复用动态探测的 Python 解释器

**Date**: 2026-09-03
**Task**: Support Antigravity lifecycle hooks in Trellis CLI
**Package**: cli
**Branch**: `feat/antigravity-hooks`

### Summary

处理 CodeRabbit 评审反馈:在 Antigravity 集成测试中使用 getPythonCommandForPlatform 动态解析 Python 解释器。

### Main Changes

- 在 `inject-workflow-state-antigravity.integration.test.ts` 中引入 `getPythonCommandForPlatform`
- 消除 `hasPython()` 与子进程调用中硬编码的 `python3`,增强跨平台兼容性

### Git Commits

| Hash | Message |
|------|---------|
| `9c011a9a` | test(antigravity): 在集成测试中复用动态探测的 Python 解释器 |

### Testing

- [OK] 1900 CLI 测试全量通过

### Status

[OK] **Completed**

### Next Steps

- 等待上游 PR #600 合并
16 changes: 14 additions & 2 deletions packages/cli/src/configurators/antigravity.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import { AI_TOOLS } from "../types/ai-tools.js";
import { collectBothTemplates } from "./shared.js";
import {
collectBothTemplates,
collectSharedHooks,
resolvePlaceholders,
} from "./shared.js";
import { getHooksConfig } from "../templates/antigravity/index.js";

/**
* The Antigravity file set — written at init and diffed by `trellis update`.
* - workflows/ — start + finish-work as slash commands
* - skills/trellis-{name}/SKILL.md — auto-triggered skills from `common/skills/`
* - hooks/*.py — shared hook scripts (inject-workflow-state.py, inject-shell-session-context.py)
* - hooks.json — Antigravity lifecycle hooks configuration
*/
export function collectAntigravityTemplates(): Map<string, string> {
return collectBothTemplates(
const files = collectBothTemplates(
AI_TOOLS.antigravity.templateContext,
(n) => `.agent/workflows/${n}.md`,
".agent/skills",
);
for (const [k, v] of collectSharedHooks(".agent/hooks", "antigravity")) {
files.set(k, v);
}
files.set(".agent/hooks.json", resolvePlaceholders(getHooksConfig()));
return files;
}
23 changes: 23 additions & 0 deletions packages/cli/src/templates/antigravity/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"trellis": {
"PreInvocation": [
{
"type": "command",
"command": "{{PYTHON_CMD}} hooks/inject-workflow-state.py",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"timeout": 15
}
],
"PreToolUse": [
{
"matcher": "run_command",
"hooks": [
{
"type": "command",
"command": "{{PYTHON_CMD}} hooks/inject-shell-session-context.py",
"timeout": 10
}
]
}
]
}
}
13 changes: 13 additions & 0 deletions packages/cli/src/templates/antigravity/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Antigravity templates
*
* Directory structure:
* antigravity/
* └── hooks.json # Lifecycle hooks configuration
*/

import { createTemplateReader } from "../template-utils.js";

const { getConfig } = createTemplateReader(import.meta.url);

export const getHooksConfig = (): string => getConfig("hooks.json");
Loading