| Title: | Artificial Intelligence Workflow Tools |
|---|---|
| Description: | Manage skills for large language model coding agents. Supports installing skills from 'GitHub' or local directories, tracking versions in a lock file, and keeping installations current. Installations can be scoped to a single project or shared globally across projects. |
| Authors: | Christopher T. Kenny [aut, cre] (ORCID: <https://orcid.org/0000-0002-9386-6860>) |
| Maintainer: | Christopher T. Kenny <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-05-20 21:51:24 UTC |
| Source: | https://github.com/christopherkenny/wf |
Installs a custom agent from a GitHub repository or a local file into an
agents directory. Agents are single Markdown files with YAML frontmatter
specifying at minimum a name and description.
add_agent(source, agent = NULL, path = NULL, overwrite = FALSE)add_agent(source, agent = NULL, path = NULL, overwrite = FALSE)
source |
One of:
|
agent |
The agent to install. One of:
|
path |
The agents directory. Can be one of:
|
overwrite |
If |
The path to the installed agent file, invisibly.
src <- tempfile(fileext = '.md') writeLines( c('---', 'name: example', 'description: An example agent.', '---'), src ) add_agent(src, path = tempfile())src <- tempfile(fileext = '.md') writeLines( c('---', 'name: example', 'description: An example agent.', '---'), src ) add_agent(src, path = tempfile())
Installs a hook script from a GitHub repository or a local file into a
hooks directory, then registers it in the corresponding settings.json
so it runs on the specified lifecycle event.
add_hook( source, event, hook = NULL, matcher = NULL, path = NULL, settings = NULL, overwrite = FALSE, timeout = NULL, async = FALSE )add_hook( source, event, hook = NULL, matcher = NULL, path = NULL, settings = NULL, overwrite = FALSE, timeout = NULL, async = FALSE )
source |
One of:
|
event |
The lifecycle event to attach the hook to. One of
|
hook |
For multi-hook repositories that store scripts under a
|
matcher |
An optional tool-name pattern (for |
path |
The hooks directory. Can be one of:
|
settings |
Path to the |
overwrite |
If |
timeout |
Optional timeout in seconds for the hook command. |
async |
If |
The path to the installed hook script, invisibly.
tmp_hook <- tempfile(fileext = '.sh') writeLines(c('#!/bin/bash', 'echo hello'), tmp_hook) tmp_dir <- tempfile() tmp_settings <- tempfile(fileext = '.json') add_hook(tmp_hook, event = 'PreToolUse', path = tmp_dir, settings = tmp_settings )tmp_hook <- tempfile(fileext = '.sh') writeLines(c('#!/bin/bash', 'echo hello'), tmp_hook) tmp_dir <- tempfile() tmp_settings <- tempfile(fileext = '.json') add_hook(tmp_hook, event = 'PreToolUse', path = tmp_dir, settings = tmp_settings )
Installs a rule from a GitHub repository or a local file into a rules
directory. Rules are Markdown files with optional YAML frontmatter. The
rule name comes from the frontmatter if present, otherwise from the
filename stem.
add_rule(source, rule = NULL, path = NULL, overwrite = FALSE)add_rule(source, rule = NULL, path = NULL, overwrite = FALSE)
source |
One of:
|
rule |
The rule to install. One of:
|
path |
The rules directory. Can be one of:
|
overwrite |
If |
The path to the installed rule file, invisibly.
src <- tempfile(fileext = '.md') writeLines( c('---', 'name: example', 'description: An example rule.', '---'), src ) add_rule(src, path = tempfile())src <- tempfile(fileext = '.md') writeLines( c('---', 'name: example', 'description: An example rule.', '---'), src ) add_rule(src, path = tempfile())
Installs a skill from a GitHub repository or a local directory into a skills directory.
add_skill(source, skill = NULL, path = NULL, overwrite = FALSE)add_skill(source, skill = NULL, path = NULL, overwrite = FALSE)
source |
One of:
|
skill |
The skill to install. One of:
|
path |
The skills directory. Can be one of:
|
overwrite |
If |
The path to the installed skill directory, invisibly.
src <- tempfile() dir.create(src) writeLines( c('---', 'name: example', 'description: An example skill.', '---'), file.path(src, 'SKILL.md') ) add_skill(src, path = tempfile())src <- tempfile() dir.create(src) writeLines( c('---', 'name: example', 'description: An example skill.', '---'), file.path(src, 'SKILL.md') ) add_skill(src, path = tempfile())
Returns the conventional directory path where custom agents for a given
coding agent are stored. The path is not expanded (i.e., ~ is not
resolved to the home directory). Use fs::path_expand() if you need an
absolute path.
agent_path(agent = NULL, scope = c("project", "global"))agent_path(agent = NULL, scope = c("project", "global"))
agent |
One of |
scope |
One of |
A length-1 character vector giving the conventional agents path.
agent_path('claude_code', 'project') agent_path('claude', 'project') # alias for claude_code agent_path('cursor', 'global') agent_path() # auto-detects from WF_AGENT, dir scan, or falls back to claude_codeagent_path('claude_code', 'project') agent_path('claude', 'project') # alias for claude_code agent_path('cursor', 'global') agent_path() # auto-detects from WF_AGENT, dir scan, or falls back to claude_code
Compares each installed agent's recorded commit SHA against the latest commit on GitHub. Local agents are reported as not updatable.
check_agents(path = NULL)check_agents(path = NULL)
path |
The agents directory. Can be one of:
|
A data frame with columns:
name: agent name.
installed_sha: the SHA recorded at install time (NA for local).
latest_sha: the current HEAD SHA on GitHub (NA for local or on
network failure).
update_available: TRUE if installed and latest SHAs differ.
check_agents(tempfile())check_agents(tempfile())
Compares each installed hook's recorded commit SHA against the latest commit on GitHub. Local hooks are reported as not updatable.
check_hooks(path = NULL)check_hooks(path = NULL)
path |
The hooks directory. Can be one of:
|
A data frame with columns:
name: hook name.
installed_sha: the SHA recorded at install time (NA for local).
latest_sha: the current HEAD SHA on GitHub (NA for local or on
network failure).
update_available: TRUE if installed and latest SHAs differ.
check_hooks(tempfile())check_hooks(tempfile())
Compares each installed rule's recorded commit SHA against the latest commit on GitHub. Local rules are reported as not updatable.
check_rules(path = NULL)check_rules(path = NULL)
path |
The rules directory. Can be one of:
|
A data frame with columns:
name: rule name.
installed_sha: the SHA recorded at install time (NA for local).
latest_sha: the current HEAD SHA on GitHub (NA for local or on
network failure).
update_available: TRUE if installed and latest SHAs differ.
check_rules(tempfile())check_rules(tempfile())
Compares each installed skill's recorded commit SHA against the latest commit on GitHub. Local skills are reported as not updatable.
check_skills(path = NULL)check_skills(path = NULL)
path |
The skills directory. Can be one of:
|
A data frame with columns:
name: skill name.
installed_sha: the SHA recorded at install time (NA for local).
latest_sha: the current HEAD SHA on GitHub (NA for local or on
network failure).
update_available: TRUE if installed and latest SHAs differ.
check_skills(tempfile())check_skills(tempfile())
Searches GitHub for repositories tagged with an agent topic and matching
a keyword query. Searches across all supported agent topic conventions
(e.g. claude-agent, cursor-agent).
find_agent(query)find_agent(query)
query |
Keyword to search for. |
A data frame with columns:
name: repository name.
description: repository description.
owner: repository owner login.
url: full URL of the repository.
stars: number of GitHub stars.
## Not run: # Requires GitHub API access; may fail due to rate limiting find_agent('code-review') ## End(Not run)## Not run: # Requires GitHub API access; may fail due to rate limiting find_agent('code-review') ## End(Not run)
Searches GitHub for repositories tagged with a hook topic and matching
a keyword query. Searches across all supported hook topic conventions
(e.g. claude-hook, cursor-hook).
find_hook(query)find_hook(query)
query |
Keyword to search for. |
A data frame with columns:
name: repository name.
description: repository description.
owner: repository owner login.
url: full URL of the repository.
stars: number of GitHub stars.
## Not run: # Requires GitHub API access; may fail due to rate limiting find_hook('linting') ## End(Not run)## Not run: # Requires GitHub API access; may fail due to rate limiting find_hook('linting') ## End(Not run)
Searches GitHub for repositories tagged with a rule topic and matching
a keyword query. Searches across all supported rule topic conventions
(e.g. claude-rule, cursor-rule).
find_rule(query)find_rule(query)
query |
Keyword to search for. |
A data frame with columns:
name: repository name.
description: repository description.
owner: repository owner login.
url: full URL of the repository.
stars: number of GitHub stars.
## Not run: # Requires GitHub API access; may fail due to rate limiting find_rule('testing') ## End(Not run)## Not run: # Requires GitHub API access; may fail due to rate limiting find_rule('testing') ## End(Not run)
Searches GitHub for repositories tagged with a skill topic and matching
a keyword query. Searches across all supported agent topic conventions
(e.g. claude-skill, cursor-skill).
find_skill(query)find_skill(query)
query |
Keyword to search for. |
A data frame with columns:
name: repository name.
description: repository description.
owner: repository owner login.
url: full URL of the repository.
stars: number of GitHub stars.
## Not run: # Requires GitHub API access; may fail due to rate limiting find_skill('rstats') ## End(Not run)## Not run: # Requires GitHub API access; may fail due to rate limiting find_skill('rstats') ## End(Not run)
Returns the conventional directory path where hook scripts for a given
coding agent are stored. The path is not expanded (i.e., ~ is not
resolved to the home directory). Use fs::path_expand() if you need an
absolute path.
hook_path(agent = NULL, scope = c("project", "global"))hook_path(agent = NULL, scope = c("project", "global"))
agent |
One of |
scope |
One of |
A length-1 character vector giving the conventional hooks directory path.
hook_path('claude_code', 'project') hook_path('claude', 'global') # alias for claude_code hook_path('cursor', 'project') hook_path() # auto-detects from WF_AGENT, dir scan, or falls back to claude_codehook_path('claude_code', 'project') hook_path('claude', 'global') # alias for claude_code hook_path('cursor', 'project') hook_path() # auto-detects from WF_AGENT, dir scan, or falls back to claude_code
Creates a new agent file at path/name.md containing a template ready to
be filled in.
init_agent(name, path = NULL)init_agent(name, path = NULL)
name |
Agent name. Must be 1-64 characters, lowercase alphanumeric
with single hyphens (no consecutive |
path |
Directory in which to create the agent file. Can be one of:
|
The path to the new agent file, invisibly.
init_agent('my-agent', tempfile())init_agent('my-agent', tempfile())
Creates a new shell script hook file at path/name.sh containing a
minimal template ready to be filled in. After editing the script,
register it with register_hook() or install it with add_hook().
init_hook(name, path = NULL)init_hook(name, path = NULL)
name |
Hook name. Must be 1-64 characters, lowercase alphanumeric
with single hyphens (no consecutive |
path |
Directory in which to create the hook file. Can be one of:
|
The path to the new hook file, invisibly.
init_hook('my-hook', tempfile())init_hook('my-hook', tempfile())
Creates a new rule file at path/name.md containing a template ready to
be filled in.
init_rule(name, path = NULL)init_rule(name, path = NULL)
name |
Rule name. Must be 1-64 characters, lowercase alphanumeric
with single hyphens (no consecutive |
path |
Directory in which to create the rule file. Can be one of:
|
The path to the new rule file, invisibly.
init_rule('my-rule', tempfile())init_rule('my-rule', tempfile())
Creates a new skill directory at path/name/ containing a template
SKILL.md file ready to be filled in.
init_skill(name, path = NULL)init_skill(name, path = NULL)
name |
Skill name. Must be 1-64 characters, lowercase alphanumeric with
single hyphens (no consecutive |
path |
Directory in which to create the skill. The skill directory
itself will be
|
The path to the new skill directory, invisibly.
init_skill('my-skill', tempfile())init_skill('my-skill', tempfile())
Returns a data frame describing all agents installed in an agents directory.
list_agents(path = NULL)list_agents(path = NULL)
path |
The agents directory. Can be one of:
|
A data frame with columns:
name: agent name from frontmatter (or filename stem).
description: agent description from frontmatter.
source: the source URL or local path the agent was installed from.
installed_at: ISO 8601 timestamp of when the agent was installed.
list_agents(tempfile())list_agents(tempfile())
Returns a data frame of all hooks configured in a coding agent's
settings.json file.
list_hooks( path = NULL, settings = NULL, agent = NULL, scope = c("project", "local", "global") )list_hooks( path = NULL, settings = NULL, agent = NULL, scope = c("project", "local", "global") )
path |
The hooks directory. When supplied, the
|
settings |
Path to the |
agent, scope
|
Passed to |
A data frame with columns:
event: the lifecycle event name (e.g. "PreToolUse").
matcher: the tool-name pattern, or NA if none.
command: the shell command to execute.
file: path to the installed script file, or NA if not tracked.
tmp <- tempfile(fileext = '.json') register_hook('PreToolUse', 'echo hello', path = tmp) list_hooks(settings = tmp)tmp <- tempfile(fileext = '.json') register_hook('PreToolUse', 'echo hello', path = tmp) list_hooks(settings = tmp)
Returns a data frame describing all rules installed in a rules directory.
list_rules(path = NULL)list_rules(path = NULL)
path |
The rules directory. Can be one of:
|
A data frame with columns:
name: rule name from frontmatter (or filename stem).
description: rule description from frontmatter.
source: the source URL or local path the rule was installed from.
installed_at: ISO 8601 timestamp of when the rule was installed.
list_rules(tempfile())list_rules(tempfile())
Returns a data frame describing all skills installed in a skills directory.
list_skills(path = NULL)list_skills(path = NULL)
path |
The skills directory. Can be one of:
|
A data frame with columns:
name: skill name from frontmatter (or filename stem).
description: skill description from frontmatter.
source: the source URL or local path the skill was installed from.
installed_at: ISO 8601 timestamp of when the skill was installed.
list_skills(tempfile())list_skills(tempfile())
Adds a shell command hook to a coding agent's settings.json file. Hooks
run automatically on agent events such as "PreToolUse" or
"UserPromptSubmit". To install a hook script from GitHub or a local
file, use add_hook() instead.
register_hook( event, command, matcher = NULL, timeout = NULL, async = FALSE, agent = NULL, scope = c("project", "local", "global"), path = NULL )register_hook( event, command, matcher = NULL, timeout = NULL, async = FALSE, agent = NULL, scope = c("project", "local", "global"), path = NULL )
event |
The lifecycle event to attach the hook to. One of
|
command |
The shell command to execute when the hook fires. |
matcher |
An optional tool-name pattern (for |
timeout |
Optional timeout in seconds for the hook command. |
async |
If |
agent, scope, path
|
Passed to |
The path to the modified settings file, invisibly.
tmp <- tempfile(fileext = '.json') register_hook('PreToolUse', 'echo hello', path = tmp)tmp <- tempfile(fileext = '.json') register_hook('PreToolUse', 'echo hello', path = tmp)
Deletes an agent file from an agents directory and removes it from the lock file.
remove_agent(name, path = NULL, force = FALSE)remove_agent(name, path = NULL, force = FALSE)
name |
The name of the agent to remove (without the |
path |
The agents directory. Can be one of:
|
force |
If |
The name of the removed agent, invisibly.
src <- tempfile(fileext = '.md') writeLines( c('---', 'name: example', 'description: An example agent.', '---'), src ) tmp <- tempfile() add_agent(src, path = tmp) remove_agent('example', tmp, force = TRUE)src <- tempfile(fileext = '.md') writeLines( c('---', 'name: example', 'description: An example agent.', '---'), src ) tmp <- tempfile() add_agent(src, path = tmp) remove_agent('example', tmp, force = TRUE)
Deletes a hook script from the hooks directory, removes its registration
from settings.json, and removes it from the lock file.
remove_hook(name, path = NULL, settings = NULL, force = FALSE)remove_hook(name, path = NULL, settings = NULL, force = FALSE)
name |
The name of the hook to remove (the script filename stem,
e.g. |
path |
The hooks directory. Can be one of:
|
settings |
Path to the |
force |
If |
The name of the removed hook, invisibly.
tmp_hook <- tempfile(fileext = '.sh') writeLines(c('#!/bin/bash', 'echo hello'), tmp_hook) tmp_dir <- tempfile() tmp_settings <- tempfile(fileext = '.json') add_hook(tmp_hook, event = 'PreToolUse', path = tmp_dir, settings = tmp_settings ) remove_hook(fs::path_ext_remove(basename(tmp_hook)), tmp_dir, settings = tmp_settings, force = TRUE )tmp_hook <- tempfile(fileext = '.sh') writeLines(c('#!/bin/bash', 'echo hello'), tmp_hook) tmp_dir <- tempfile() tmp_settings <- tempfile(fileext = '.json') add_hook(tmp_hook, event = 'PreToolUse', path = tmp_dir, settings = tmp_settings ) remove_hook(fs::path_ext_remove(basename(tmp_hook)), tmp_dir, settings = tmp_settings, force = TRUE )
Deletes a rule file from a rules directory and removes it from the lock file.
remove_rule(name, path = NULL, force = FALSE)remove_rule(name, path = NULL, force = FALSE)
name |
The name of the rule to remove (without the |
path |
The rules directory. Can be one of:
|
force |
If |
The name of the removed rule, invisibly.
src <- tempfile(fileext = '.md') writeLines( c('---', 'name: example', 'description: An example rule.', '---'), src ) tmp <- tempfile() add_rule(src, path = tmp) remove_rule('example', tmp, force = TRUE)src <- tempfile(fileext = '.md') writeLines( c('---', 'name: example', 'description: An example rule.', '---'), src ) tmp <- tempfile() add_rule(src, path = tmp) remove_rule('example', tmp, force = TRUE)
Deletes a skill directory from a skills directory and removes it from the lock file.
remove_skill(name, path = NULL, force = FALSE)remove_skill(name, path = NULL, force = FALSE)
name |
The name of the skill to remove. |
path |
The skills directory. Can be one of:
|
force |
If |
The name of the removed skill, invisibly.
src <- tempfile() dir.create(src) writeLines( c('---', 'name: example', 'description: An example skill.', '---'), file.path(src, 'SKILL.md') ) tmp <- tempfile() add_skill(src, path = tmp) remove_skill('example', tmp, force = TRUE)src <- tempfile() dir.create(src) writeLines( c('---', 'name: example', 'description: An example skill.', '---'), file.path(src, 'SKILL.md') ) tmp <- tempfile() add_skill(src, path = tmp) remove_skill('example', tmp, force = TRUE)
Returns the conventional directory path where rules for a given coding
agent are stored. The path is not expanded (i.e., ~ is not resolved to
the home directory). Use fs::path_expand() if you need an absolute path.
rule_path(agent = NULL, scope = c("project", "global"))rule_path(agent = NULL, scope = c("project", "global"))
agent |
One of |
scope |
One of |
A length-1 character vector giving the conventional rules path.
rule_path('claude_code', 'project') rule_path('claude', 'project') # alias for claude_code rule_path('cursor', 'global') rule_path() # auto-detects from WF_AGENT, dir scan, or falls back to claude_coderule_path('claude_code', 'project') rule_path('claude', 'project') # alias for claude_code rule_path('cursor', 'global') rule_path() # auto-detects from WF_AGENT, dir scan, or falls back to claude_code
Returns the path to the settings.json file where hooks are configured
for a given coding agent and scope. The path is not expanded (i.e., ~
is not resolved to the home directory). Use fs::path_expand() if you
need an absolute path.
settings_path(agent = NULL, scope = c("project", "local", "global"))settings_path(agent = NULL, scope = c("project", "local", "global"))
agent |
One of |
scope |
One of:
|
A length-1 character vector giving the path to the settings file.
settings_path('claude_code', 'project') settings_path('claude', 'local') # alias for claude_code settings_path('cursor', 'global')settings_path('claude_code', 'project') settings_path('claude', 'local') # alias for claude_code settings_path('cursor', 'global')
Returns the conventional directory path where skills for a given agent are
stored. The path is not expanded (i.e., ~ is not resolved to the home
directory). Use fs::path_expand() if you need an absolute path.
skill_path(agent = NULL, scope = c("project", "global"))skill_path(agent = NULL, scope = c("project", "global"))
agent |
One of |
scope |
One of |
A length-1 character vector giving the conventional skill path.
skill_path('claude_code', 'project') skill_path('claude', 'project') # alias for claude_code skill_path('github_copilot', 'project') skill_path('copilot', 'project') # alias for github_copilot skill_path('posit_ai', 'project') skill_path('posit', 'project') # alias for posit_ai skill_path('cursor', 'global') skill_path() # auto-detects from WF_AGENT, dir scan, or falls back to claude_codeskill_path('claude_code', 'project') skill_path('claude', 'project') # alias for claude_code skill_path('github_copilot', 'project') skill_path('copilot', 'project') # alias for github_copilot skill_path('posit_ai', 'project') skill_path('posit', 'project') # alias for posit_ai skill_path('cursor', 'global') skill_path() # auto-detects from WF_AGENT, dir scan, or falls back to claude_code
Checks each installed agent for available updates and re-installs any that have a newer version on GitHub.
update_agents(path = NULL)update_agents(path = NULL)
path |
The agents directory to update. Can be one of:
|
A character vector of updated agent names, invisibly.
update_agents(tempfile())update_agents(tempfile())
Checks each installed hook for available updates and re-installs any that have a newer version on GitHub.
update_hooks(path = NULL, settings = NULL)update_hooks(path = NULL, settings = NULL)
path |
The hooks directory to update. Can be one of:
|
settings |
Path to the |
A character vector of updated hook names, invisibly.
update_hooks(tempfile())update_hooks(tempfile())
Checks each installed rule for available updates and re-installs any that have a newer version on GitHub.
update_rules(path = NULL)update_rules(path = NULL)
path |
The rules directory to update. Can be one of:
|
A character vector of updated rule names, invisibly.
update_rules(tempfile())update_rules(tempfile())
Checks each installed skill for available updates and re-installs any that have a newer version on GitHub.
update_skills(path = NULL)update_skills(path = NULL)
path |
The skills directory to update. Can be one of:
|
A character vector of updated skill names, invisibly.
update_skills(tempfile())update_skills(tempfile())