Skip to content

Conversation

@forketyfork
Copy link
Owner

Add architect hook install|uninstall|status commands to automate
setting up hooks for Claude Code, Codex, and Gemini CLI.

This eliminates the manual process of copying scripts and editing
configuration files. The commands:

  • Copy notification scripts to the tool's config directory
  • Update settings.json (Claude/Gemini) or config.toml (Codex)
  • Show installation status across all supported tools

New modules:

  • src/cli.zig: CLI argument parser
  • src/hook_manager.zig: Hook installation/uninstallation logic

Usage:
architect hook install claude
architect hook uninstall gemini
architect hook status

Add `architect hook install|uninstall|status` commands to automate
setting up hooks for Claude Code, Codex, and Gemini CLI.

This eliminates the manual process of copying scripts and editing
configuration files. The commands:
- Copy notification scripts to the tool's config directory
- Update settings.json (Claude/Gemini) or config.toml (Codex)
- Show installation status across all supported tools

New modules:
- src/cli.zig: CLI argument parser
- src/hook_manager.zig: Hook installation/uninstallation logic

Usage:
  architect hook install claude
  architect hook uninstall gemini
  architect hook status
@forketyfork forketyfork requested a review from Copilot January 17, 2026 15:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a CLI interface to Architect for managing AI assistant hook installations. The feature automates the previously manual process of copying notification scripts and editing configuration files for Claude Code, Codex, and Gemini CLI.

Changes:

  • New CLI argument parsing system supporting hook install|uninstall|status commands, help, and version display
  • Hook manager module that handles copying scripts, updating JSON/TOML configs, and checking installation status
  • Modified main entry point to handle CLI commands before GUI initialization

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/main.zig Added CLI argument parsing and routing before GUI initialization
src/cli.zig New CLI parser with Tool/Command types and usage/error messages
src/hook_manager.zig New hook installation logic for Claude/Codex/Gemini config management
docs/development.md Added automated installation section with CLI examples
docs/architecture.md Updated runtime flow and file structure to document CLI routing
README.md Added CLI Commands section with usage examples
CLAUDE.md Added reference to automated hook installation command

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return;
} else {
// Append notify line
const out_file = std.fs.createFileAbsolute(config_path, .{ .truncate = false }) catch return error.ConfigWriteFailed;
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When opening a file with truncate = false to append content, you should explicitly seek to the end before writing. While line 309 does call seekFromEnd(0), the seek operation could fail, and if it does, the function returns an error but the file remains open. Consider handling the seek operation before the write operations to ensure the file is closed properly on error.

Copilot uses AI. Check for mistakes.
};
const new_file = std.fs.createFileAbsolute(config_path, .{}) catch return error.ConfigWriteFailed;
defer new_file.close();
const notify_line = try std.fmt.allocPrint(allocator, "notify = [\"python3\", \"{s}\"]\n", .{script_path});
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same TOML notify line format string appears twice in this file. Consider extracting it to a constant to avoid duplication and ensure consistency if the format needs to change.

Copilot uses AI. Check for mistakes.
out_file.writeAll("\n") catch return error.ConfigWriteFailed;
}

const notify_line = std.fmt.allocPrint(allocator, "notify = [\"python3\", \"{s}\"]\n", .{script_path}) catch return error.OutOfMemory;
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same TOML notify line format string appears twice in this file. Consider extracting it to a constant to avoid duplication and ensure consistency if the format needs to change.

Copilot uses AI. Check for mistakes.

if (root != .object) return error.JsonParseFailed;

// Build hook configuration
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Claude 'done' command includes '|| true' for error handling while the Gemini version does not. This inconsistency may be intentional but should be documented or unified if both should handle failures the same way.

Suggested change
// Build hook configuration
// Build hook configuration
// Note: These commands are used for the Claude hooks and intentionally append
// "|| true" so that a non-zero exit status from the hook script does not cause
// the calling CLI to fail. Gemini hooks are configured elsewhere without
// "|| true" and rely on their own error-handling semantics.

Copilot uses AI. Check for mistakes.
if (root != .object) return error.JsonParseFailed;

// Build commands
const after_cmd = try std.fmt.allocPrint(alloc, "python3 {s} done", .{script_path});
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Claude 'done' command includes '|| true' for error handling while the Gemini version does not. This inconsistency may be intentional but should be documented or unified if both should handle failures the same way.

Suggested change
const after_cmd = try std.fmt.allocPrint(alloc, "python3 {s} done", .{script_path});
const after_cmd = try std.fmt.allocPrint(alloc, "python3 {s} done || true", .{script_path});

Copilot uses AI. Check for mistakes.

if (root != .object) return error.JsonParseFailed;

// Build hook configuration
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the 'done' commands, the Claude notification command includes '|| true' while Gemini's does not. Consider documenting why the error handling differs between tools or making them consistent.

Suggested change
// Build hook configuration
// Build hook configuration
// NOTE:
// These Claude hook commands intentionally append `|| true` so that a failure
// in the Python helper script does not cause the outer CLI hook to fail.
// Gemini's hooks are configured separately and may omit `|| true` because
// they manage errors differently; this difference is intentional.

Copilot uses AI. Check for mistakes.

// Build commands
const after_cmd = try std.fmt.allocPrint(alloc, "python3 {s} done", .{script_path});
const notif_cmd = try std.fmt.allocPrint(alloc, "python3 {s} awaiting_approval", .{script_path});
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the 'done' commands, the Claude notification command includes '|| true' while Gemini's does not. Consider documenting why the error handling differs between tools or making them consistent.

Suggested change
const notif_cmd = try std.fmt.allocPrint(alloc, "python3 {s} awaiting_approval", .{script_path});
const notif_cmd = try std.fmt.allocPrint(alloc, "python3 {s} awaiting_approval || true", .{script_path});

Copilot uses AI. Check for mistakes.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bffd74f551

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 302 to 305
} else if (std.mem.indexOf(u8, content, "notify")) |_| {
// There's a different notify config - don't overwrite it
return;
} else {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid silent no-op when Codex notify already exists

If config.toml already contains any notify setting (even unrelated or commented), installCodexHooks returns early without updating the file, yet the caller still prints “Updated …” and “Hook installed.” This makes architect hook install codex succeed while leaving the hook unconfigured, so users with an existing notify (a common setup) will not get status updates. Consider either merging/appending the Architect notifier or returning a dedicated error so the CLI can report that install was skipped.

Useful? React with 👍 / 👎.

Address PR review comments:
- Return HookSkipped error when Codex config already has a notify
  setting, allowing CLI to inform user of manual merge needed
- Add || true to Gemini hook commands for consistent error handling

Fix Zig 0.15 API compatibility:
- Update std.json.stringify to use std.json.Stringify.value
- Update ArrayList API: use {} initializer, pass allocator to methods
- Update std.fs.selfExePath to use buffer instead of allocator
- Update std.io.getStdErr/getStdOut to std.fs.File.stderr/stdout
- Simplify directory existence checks using realpath directly
- Fix variable shadowing in main.zig (command -> worktree_cmd, remove_cmd)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants