Skip to content

feat(cli): add service subcommand for systemd user service management#23

Merged
MarvelNwachukwu merged 3 commits into
mainfrom
feat/service-command
Feb 19, 2026
Merged

feat(cli): add service subcommand for systemd user service management#23
MarvelNwachukwu merged 3 commits into
mainfrom
feat/service-command

Conversation

@MarvelNwachukwu
Copy link
Copy Markdown
Contributor

Adds adk-claw service with install, uninstall, start, stop, restart, status, and logs subcommands. The install flow writes a user-level systemd service file (~/.config/systemd/user/adk-claw.service), enables linger so the service survives SSH logout, and embeds the install-time PATH so nvm-managed node is found correctly at runtime.

Adds `adk-claw service` with install, uninstall, start, stop, restart,
status, and logs subcommands. The install flow writes a user-level
systemd service file (~/.config/systemd/user/adk-claw.service), enables
linger so the service survives SSH logout, and embeds the install-time
PATH so nvm-managed node is found correctly at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @MarvelNwachukwu, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the adk-claw CLI by integrating robust systemd user service management capabilities. It allows users to easily install, control, and monitor the adk-claw application as a background service, improving its reliability and ease of use, especially in environments where the application needs to run persistently across sessions.

Highlights

  • New service CLI command: Introduced a new adk-claw service command to manage the application as a systemd user service.
  • Comprehensive Service Management: Added subcommands for install, uninstall, start, stop, restart, status, and logs to provide full control over the service lifecycle.
  • Intelligent Installation Process: The install subcommand automatically generates a systemd user service file, enables 'linger' to ensure the service persists after logout, and captures the current PATH environment variable to correctly locate Node.js binaries (e.g., from NVM).
Changelog
  • src/cli/index.ts
    • Added routing for the new service command to the main CLI entry point.
    • Updated the CLI help message and examples to include the service command and its subcommands.
  • src/cli/service.ts
    • Implemented the core logic for all adk-claw service subcommands (install, uninstall, start, stop, restart, status, logs).
    • Developed a generateServiceFile function to dynamically create systemd unit files, incorporating agent name, working directory, binary path, and environment PATH.
    • Included error handling and user prompts for a guided service management experience.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a service subcommand for managing adk-claw as a systemd user service. The implementation is comprehensive, covering installation, uninstallation, and lifecycle management commands. The installation process correctly handles systemd specifics like enabling linger and preserving the PATH environment variable.

My review focuses on improving security, robustness, and user experience. I've identified a potential command injection vulnerability and suggest using execFileSync for safer command execution. I also recommend a more efficient way to retrieve the current username and adding a platform check to ensure commands are only run on systems with systemd, providing clearer feedback to users on unsupported platforms.

Comment thread src/cli/service.ts Outdated
process.env.LOGNAME ||
execSync("whoami", { encoding: "utf-8" }).trim();
try {
execSync(`loginctl enable-linger ${username}`, { stdio: "pipe" });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Using execSync with a template literal that includes a variable can lead to command injection vulnerabilities. If the username variable contains malicious shell commands, they could be executed. It's safer to use execFileSync and pass arguments as an array to prevent shell interpretation.

You'll need to import execFileSync from node:child_process.

Suggested change
execSync(`loginctl enable-linger ${username}`, { stdio: "pipe" });
execFileSync("loginctl", ["enable-linger", username], { stdio: "pipe" });

Comment thread src/cli/service.ts
Comment on lines +27 to +30
if (!existsSync(CONFIG_PATH)) {
p.log.error("ADK Claw is not initialized. Run 'adk-claw init' first.");
process.exit(1);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The service management commands are specific to systemd, which is typically found on Linux. Running these commands on other operating systems like macOS or Windows will fail with a potentially confusing error message (e.g., systemctl not found). It would improve the user experience to add a check at the beginning of this function to ensure systemd is available and provide a clear error message if it's not.

For example, you could check for the existence of the systemctl binary before proceeding:

try {
  execSync('which systemctl', { stdio: 'pipe' });
} catch {
  p.log.error('Service management requires systemd, which was not found.');
  process.exit(1);
}

Comment thread src/cli/service.ts Outdated
Comment on lines +119 to +122
const username =
process.env.USER ||
process.env.LOGNAME ||
execSync("whoami", { encoding: "utf-8" }).trim();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Spawning a child process with execSync('whoami') to get the username is inefficient. Node.js provides a built-in, cross-platform way to get this information via os.userInfo().username. This avoids the overhead of creating a new process and is more reliable.

You'll need to import userInfo from node:os at the top of the file.

Suggested change
const username =
process.env.USER ||
process.env.LOGNAME ||
execSync("whoami", { encoding: "utf-8" }).trim();
const username = userInfo().username;

MarvelNwachukwu and others added 2 commits February 19, 2026 10:20
Dropped dead printHelp/printVersion functions (replaced by printSplash
in main). Added service entry to the splash screen command list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace execSync template literal with execFileSync for loginctl
  enable-linger to prevent command injection
- Replace execSync whoami + env vars with os.userInfo().username
  for a simpler, cross-platform username lookup
- Add systemctl existence check at the start of serviceCommand to
  give a clear error on non-systemd systems instead of a cryptic failure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@MarvelNwachukwu MarvelNwachukwu merged commit 323e0be into main Feb 19, 2026
1 check failed
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.

1 participant