| name | add-inputs |
| description | Use when the user asks to add one or more GitHub/GitLab repositories or an entire GitHub organization to the hybrid-platforms-inputs inventory. Adds entries to the appropriate segment CSV files and generates matching owners.csv rows. |
| argument-hint | <repo-or-org-url> [--segment <segment>] [--inventory <path-or-url>] |
Add Inputs — Register Repositories in the Inventory
This skill adds one or more repositories (or every public repository in a
GitHub organization) to the hybrid-platforms-inputs inventory so that
downstream skills (security audits, triaging, repo-graph, dashboards) can
discover and operate on them.
It is the lightweight counterpart of inventory-repositories, which
discovers repos automatically from upstream sources. This skill is for
ad-hoc additions — repos or orgs the user explicitly wants tracked.
Constraints
- Do not execute arbitrary code on cloned repositories.
- Do not remove or overwrite existing CSV rows; only append new entries.
- All file writes are confined to the inventory repository.
- Resolve
<harness> as the ai-security-harness/ repo root and
<inventory> as the hybrid-platforms-inputs/ sibling repo (or the
user-provided path/URL).
Arguments
Parse $ARGUMENTS as a space-separated token list:
| Token | Required | Description |
|---|
<repo-or-org> | yes | One or more GitHub/GitLab repository URLs (e.g. https://github.com/org/repo) or a GitHub organization URL / name (e.g. https://github.com/openshift or just openshift). Multiple values may be space-separated. |
--segment <name> | no | Target segment directory inside the inventory (services, openshift, operator-catalog, or any custom name). Defaults to adhoc. |
--inventory <path> | no | Path (local) or HTTPS clone URL for the inventory repository. Defaults to https://gitlab.cee.redhat.com/hybrid-platforms-sec/hybrid-platforms-inputs. When a URL is given, the skill clones it into <workspace>/hybrid-platforms-inputs/ if not already present. |
--sub-service <name> | no | Value for the App/Sub-Service CSV column (services segment only). Defaults to the organization name. |
--dry-run | no | Print what would be added without writing any files. |
Step 0 — Resolve the inventory repository
- If
--inventory is a local path, use it directly.
- If
--inventory is an HTTPS/SSH URL (or the default), check whether
hybrid-platforms-inputs/ exists as a sibling of <harness>.
- Verify the directory exists and is writable. Abort with a clear error if
not.
Set INVENTORY to the resolved absolute path.
Step 1 — Classify and expand inputs
For each positional argument in <repo-or-org>:
Single repository URL
A URL containing at least <host>/<org>/<repo> (e.g.
https://github.com/openshift/api).
Normalize:
- Strip
.git suffix and trailing slashes.
- Resolve to canonical form:
https://<host>/<org>/<repo>.
- Extract
host, org, repo_name.
Add to the pending list as a single entry.
GitHub organization
A URL of the form https://github.com/<org> (no repo component), or a
bare organization name (no slashes).
Expand to the full list of public, non-archived, non-fork repositories
using the GitHub API:
gh repo list <org> --no-archived --source --json nameWithOwner,url --limit 1000
If gh is not available, fall back to the REST API:
Add every returned repository to the pending list.
GitLab group
A URL of the form https://<gitlab-host>/<group> (no repo component).
If the GitLab instance is accessible, list projects via the API:
GET /api/v4/groups/<group>/projects?include_subgroups=true&archived=false&per_page=100
Otherwise, ask the user to provide individual repository URLs.
Step 2 — Determine the target segment
If --segment was provided, use it. Otherwise:
| Condition | Segment |
|---|
All repos are under a known OpenShift-ecosystem org (see org table in inventory-repositories skill) | openshift |
All repos are operator-related (name contains operator) | operator-catalog |
| Default | adhoc |
Create the segment directory under INVENTORY if it does not exist.
For the adhoc segment, organize repos under
INVENTORY/adhoc/<org>/ — one directory per organization.
For existing segments (openshift, operator-catalog, services), place
files according to the conventions documented in the
inventory-repositories skill.
Step 3 — Deduplicate against existing inventory
Before writing, scan all existing *-repos.csv files under the target
segment directory. Build a set of canonical URLs already present.
Skip any repo from the pending list whose canonical URL already exists.
Report skipped duplicates to the user.
Step 4 — Write the CSV inventory
File location
| Segment | Path |
|---|
adhoc | INVENTORY/adhoc/<org>/<org>-repos.csv |
services | INVENTORY/services/<sub-service>/<sub-service>-repos.csv |
openshift | INVENTORY/openshift/adhoc-repos.csv |
operator-catalog | INVENTORY/operator-catalog/<org>/<org>-repos.csv |
Column schema
Use the segment-appropriate schema. For adhoc and general use:
Repository,URL,Host,Organization/Group,Repo Name,App/Sub-Service,Resource Type
Field rules:
Repository = <org>/<repo> (no host prefix)
URL = full HTTPS URL
Host = GitHub or GitLab (derived from the URL host)
Organization/Group = the GitHub org or GitLab group
Repo Name = the repository name
App/Sub-Service = value from --sub-service, or the org name
Resource Type = adhoc
If the CSV file already exists, append new rows (do not rewrite the
header). If it does not exist, write the header row first.
Sort appended rows by Organization/Group, then Repo Name.
Step 5 — Generate or update owners.csv
For each newly added repository, create or append to an owners.csv in the
same directory as the repos CSV.
Schema
Repository,URL,Host,Owner Team,Manager,Individual Owners,Ownership Source
Ownership resolution (best-effort)
Try each source in order; stop at the first that yields a team name:
-
OWNERS file — Fetch https://raw.githubusercontent.com/<org>/<repo>/HEAD/OWNERS.
Parse the YAML approvers: list. Use the first 1–2 approvers as
Individual Owners.
-
GitHub top contributors — Query
https://api.github.com/repos/<org>/<repo>/contributors?per_page=5.
Filter out bots (dependabot[bot], renovate[bot],
openshift-merge-robot, openshift-ci-robot, openshift-bot,
web-flow, github-actions[bot], mergify[bot],
red-hat-konflux[bot]). Take the top 1–2 as Individual Owners.
-
GitHub org-level mapping — Map the organization to a team using the
table in the inventory-repositories skill's
ownership resolution section.
-
Unknown — If no source yields data, set Owner Team = Unknown,
Ownership Source = none.
If owners.csv already exists, append only rows for newly added repos.
Step 6 — Commit and report
-
Stage all changed files in the inventory repository:
cd <INVENTORY> && git add -A
-
If --dry-run was specified, show git diff --cached --stat and stop
without committing.
-
Commit with a descriptive message:
add-inputs: add <N> repositories from <org(s)>
-
Print a summary to the user:
Added <N> repositories to <segment>:
- <org/repo1>
- <org/repo2>
...
Skipped <M> duplicates.
Owners resolved: <K>/<N> (source breakdown: OWNERS file: X, contributors: Y, org-map: Z)
Files modified:
<list of changed files>
To push: cd hybrid-platforms-inputs && git push
Error handling
| Condition | Action |
|---|
gh CLI not authenticated or unavailable | Fall back to unauthenticated GitHub REST API (rate-limited to 60 req/hr). Warn the user. |
| GitHub API rate limit hit | Stop expansion, report how many repos were fetched, suggest re-running with gh auth login. |
| Inventory repo not found and clone fails | Abort with a clear error including the URL tried. |
| No new repos to add (all duplicates) | Report "nothing to add" and exit cleanly. |
| GitLab group inaccessible | Ask the user to provide individual repo URLs instead. |