arbutus

arbutus is a skill for Claude Code, Codex from ualberta-rcg/drac-agent-skills. It costs 124 tokens per session (2,955 once invoked), scanned C, original, MIT.

Reference instructions for Arbutus, Alliance Canada's OpenStack cloud, and its Terraform provider. OpenStack is software for providing cloud servers, networks, storage, and related services.

In plain words
What is it for?
Use them when authenticating to Arbutus, configuring Terraform, or provisioning and operating its compute, network, storage, image, object, and file-sharing resources.
Why use it?
Arbutus has specific login, endpoint, project, and SSH details that differ from a generic OpenStack setup. The instructions document those details and common traps.

Skill for Claude CodeCodex

Written for no agent in particular: nothing here depends on one.

Good fit Use them when authenticating to Arbutus, configuring Terraform, or provisioning and operating its compute, network, storage, image, object, and file-sharing resources.

Compare 6 skills from other repositories ↓
Install with agentmods
npx agentmods add skills/ualberta-rcg/drac-agent-skills/alliance-arbutus
Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

Any agent
npx skills add ualberta-rcg/drac-agent-skills --skill alliance-arbutus
Clone the repo
git clone --depth 1 https://github.com/ualberta-rcg/drac-agent-skills

Made for: Claude Code, Codex.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for arbutus

README.md
[![agentmods](https://agentmods.dev/badge/skills/ualberta-rcg/drac-agent-skills/alliance-arbutus/github.svg)](https://agentmods.dev/skills/ualberta-rcg/drac-agent-skills/alliance-arbutus)
Your own site
<a href="https://agentmods.dev/skills/ualberta-rcg/drac-agent-skills/alliance-arbutus"><img src="https://agentmods.dev/badge/skills/ualberta-rcg/drac-agent-skills/alliance-arbutus/github.svg" alt="Measured on agentmods" height="20"></a>

Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.

agentmods 80×15 button for arbutus

Your own site · 80×15
<a href="https://agentmods.dev/skills/ualberta-rcg/drac-agent-skills/alliance-arbutus"><img src="https://agentmods.dev/badge/skills/ualberta-rcg/drac-agent-skills/alliance-arbutus.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 124 Skills are progressive disclosure: only the name and description are preloaded; the body loads when the skill is used.
When invoked 2,955 The whole file, excluding the scripts and references it only reads on demand.
Security scan C 1 finding. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.00124 $0.02955
Opus 5.5 $0.00050 $0.01182
Sonnet 5.5 $0.00025 $0.00591
Haiku 4.5 $0.00012 $0.00296

Measured 1mo ago against content hash b2542020c241, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

Grade C, and why

arbutus scanned grade C with 1 finding against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 1mo ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Cloud metadata endpointhighServer-side request forgery

One request to 169.254.169.254 can return temporary IAM credentials.

metadata service (169.254.169.254) is not reliably reachable from project subnets; without
skills/alliance-arbutus/SKILL.md · 167 lines

How it starts

The opening of the file, as written. The whole thing — 167 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Arbutus OpenStack Arbutus is AllianceCan's OpenStack cloud (Horizon: https://arbutus.cloud.computecanada.ca). atmosphere is the SSO identity provider; projects live under the default domain (e.g. def-jbaker). It is OpenStack-on-Kubernetes (the internal endpoints are *.openstack.svc.cluster.local service names), v3 identity. This skill records the cloud's actual shape (services, endpoints, flavors, volumes, networks, images, quotas) and the non-obvious traps, especially for Terraform. It is cloud-general — not tied to any single project on it. Auth & credentials No password auth — password login returns 401 (the cloud is SSO-gated). Two paths: v3websso SSO for the interactive CLI, application credentials for automation and Terraform. Path A — v3websso SSO (interactive openstack CLI) Download the RC file from Horizon: Project → API Access → Download OpenStack RC File (the Identity API v3 option). As downloaded it is not usable: it still carries an interactive password prompt (dead on this cloud) and domain vars that must go. Add these lines: export OS_AUTH_TYPE=v3websso, export OS_IDENTITY_PROVIDER=atmosphere, export OS_PROTOCOL=openid, export OS_PROJECT_DOMAIN_NAME=default. Remove export OS_USER_DOMAIN_NAME="atmosphere" (and its if [ -z "$OS_USER_DOMAIN_NAME" ]; then unset OS_USER_DOMAIN_NAME; fi guard) and the password-prompt block: echo "Please enter your OpenStack Password for project $OS_PROJECT_NAME as user $OS_USERNAME: " read -sr OS_PASSWORD_INPUT export OS_PASSWORD=$OS_PASSWORD_INPUT The corrected file then holds OS_AUTH_URL=https://identity.arbutus.alliancecan.ca/, OS_PROJECT_ID / OS_PROJECT_NAME, OS_PROJECT_DOMAIN_ID, OS_USERNAME, OS_REGION_NAME=RegionOne, OS_INTERFACE=public, OS_IDENTITY_API_VERSION=3 plus the four SSO exports above. No secret in file or env — the first command opens a browser for the OpenID login. The CLI must run from a venv with the websso plugin installed: python3 -m venv openstack source openstack/bin/activate pip install python-openstackclient keystoneauth-websso python-manilaclient Without keystoneauth-websso the v3websso auth type is unknown and every command fails. Path B — application credentials (automation, Terraform) OS_AUTH_TYPE=application_credential with OS_APPLICATION_CREDENTIAL_ID + OS_APPLICATION_CREDENTIAL_SECRET, sourced from an openrc. Never put the secret in a repo. Pre-scoped — never add a scope. Exporting OS_PROJECT_NAME / OS_USER_DOMAIN_NAME alongside an app credential fails with Application credentials cannot request a scope (HTTP 401). The credential already carries the project scope. (Exception: the Terraform provider and some CLI roles do take OS_PROJECT_NAME/OS_USER_DOMAIN_NAME; that is the provider's own auth path, not the app-credential token.) Can't list Keystone. openstack service list / openstack endpoint list → 403 identity:list_services / list_endpoints. To get the service catalog, POST to <auth_url>/v3/auth/tokens and read token.catalog from the response (the /v3/catalog endpoint 404s). The token is opaque (gAAAA...). OS_AUTH_URL is https://identity.arbutus.alliancecan.ca/ (append /v3 for the auth API). Terraform: the v3websso flow is CLI-only — for Terraform it's easier to just use application credentials; the provider won't auth from a sourced websso RC file. Service catalog (public endpoints + API version) Service Type Public endpoint nova compute https://compute.arbutus.alliancecan.ca/v2.1 neutron network https://network.arbutus.alliancecan.ca (v2) glance image https://image.arbutus.alliancecan.ca (v2) cinder volume https://volume.arbutus.alliancecan.ca/v3/<project> keystone identity https://identity.arbutus.alliancecan.ca/ (v3) swift object-store https://object-arbutus.alliancecan.ca/swift/v1/<project> heat orchestration https://orchestration.arbutus.alliancecan.ca/v1/<project> heat-cfn cloudformation https://cloudformation.arbutus.alliancecan.ca/v1 manila share https://share.arbutus.alliancecan.ca/v2 (v2) placement placement https://placement.arbutus.alliancecan.ca/ All public endpoints are HTTPS on the *.arbutus.alliancecan.ca namespace (region RegionOne). Compute is nova v2.1 (the OpenStack compute API version, not a K8s thing). Flavors Naming is <family><vcpus>-<ram>gb[-<ephemeral-gb>]. Three families, all with a 20 GB root disk and Is Public: False (per-tenant, not shared): p (persistent) — the top-of-line, no ephemeral disk, no swap (ephemeral 0, swap 0). Only the 20 GB root. Sizes: p1-1.5gb, p2-3gb, p4-4gb, p4-6gb, p4-8gb, p8-8gb, p8-12gb, p8-16gb, p16-16gb, p16-24gb, p16-32gb (16 vCPU / 32 GB is the largest). Because there is no ephemeral disk, anything large (container stores, model/data, etcd) must live on attached Cinder volumes. cm — 20 GB root plus ephemeral disk: cm1-7.5gb-35 … cm32-240gb-1120. cb — 20 GB root plus larger ephemeral: cb1-3.5gb-35 … cb96-365gb-3350. The p family's lack of ephemeral is the defining sizing constraint: a node pulling multi-GB images will fill the 20 GB root, so relocate the data to a Cinder volume (openstack_volume_attach / block device) rather than relying on disk the flavor provides. Volume types (Cinder) Only two, both public: rbd1 — the real one (Ceph RBD). This is the one to use for everything. __DEFAULT__ — the cinder default (maps to rbd1). rbd1 volumes are block storage → ReadWriteOnce (two pods on two nodes can't share a volume). There is no RWO/MRW class distinction by tier; if you create multiple StorageClasses they differ only by reclaim policy, not performance. Volume-type quotas (volumes_rbd1, gigabytes_rbd1) are -1 (unlimited) in the sample project. Availability zones Three nova AZs: compute, nova, persistent (all available). The persistent AZ is the one backing the p flavors / rbd1 storage. When scheduling to a Cinder-backed AZ, the availability_zone must match a zone that has a Cinder backend (persistent does; a compute-only zone may not). Networks External network: Public-Network (the only --external network), with three public subnets (IPv4): Public-Network-subnet: 134.87.8.0/22 Public-Network-subnet-2: 134.87.12.0/24 Public-Network-subnet-3: 206.12.96.0/21 Floating IPs are allocated from these. Router quota is 1 per project. You cannot create a second router — reuse the project's existing external router (attach interfaces to it). Don't write Terraform that provisions a fresh router; it will hit the quota. Allowed address pairs with a CIDR work. A port allowed_address_pairs entry given as a CIDR (e.g. 10.x.y.0/26) with the port's own MAC lets that port use any address in the range (used to publish secondary/VIP addresses). Verified working. When reserving a range for LB VIPs, carve it out of the subnet allocation_pool so instances can't consume those addresses. Glance images (all active, x64, 2025-08/2026 releases) Ubuntu-22.04/24.04/25.04/26.04-Resolute, Debian-12/13, Rocky-8/9/10, AlmaLinux-8/9/10, Fedora-42/44, FortiManager, and cirros. Reference images by name (data.openstack_images_image_v2 with most_recent = true + name) rather than hardcoding a UUID. Project quotas (sample def-jbaker — confirm against your allocation) cores 80, instances 20, ram 314572800 (≈300 GB), volumes 20 (rbd1 itself is -1), snapshots 10, networks 10, ports 120, subnets 10, routers 1, key-pairs 100, injected-files 10. Treat these as the hard ceiling when sizing a build; the compute ask (cores+ram) is what to confirm before a large provisioning rather than after boot. Terraform against Arbutus (terraform-provider-openstack) Provider is the community fork terraform-provider-openstack/openstack (e.g. v2.1.0), pinned in .terraform.lock.hcl. hashicorp/openstack is not in this registry and errors out pointing at the fork. Commit the lock file. config_drive = true is effectively required on openstack_compute_instance_v2. The metadata service (169.254.169.254) is not reliably reachable from project subnets; without config drive, cloud-init falls back to DataSourceNone and applies neither the user_data nor the SSH key_pair — the instance comes up with no key and no provisioning, which is a long, confusing thing to debug. Do not boot from a volume via block_device. It trips Nova's "boot sequence not valid" on this cloud. Boot the instance from the image, then attach the volume with openstack_compute_volume_attach_v2 (a separate resource, ordered after the instance). Match attached volumes by size in cloud-init, not by device name — attach order is not guaranteed, so keep per-instance volume sizes distinct and have the cloud-init look them up by size. Port resources are openstack_networking_port_v2 (the networking v2 port), not openstack_compute_port_v2. Query state/plan for the right type when inspecting ports or their allowed_address_pairs. Do not create a second router (router quota 1, above). Reference the existing external router (by name/ID) and attach the subnet to it. State backend: local terraform.tfstate (gitignored) is the working setup; a managed (e.g. GitLab) backend is aspirational — don't add a backend block unless asked. Terraform auth comes from the OS_* env: a sourced RC file plus OS_AUTH_TYPE=application_credential with the credential ID/secret (see Auth & credentials — the v3websso CLI path won't work here). The provider does accept OS_PROJECT_NAME/OS_USER_DOMAIN_NAME here even though the raw CLI app-credential token rejects a scope — don't conflate the two auth paths. openstack CLI quirks (these fail confusingly) openstack port show <p> --column allowed_address_pairs → OK. --column security_groups → invalid (use security_group_ids). openstack port set --allowed-address-pair ... → not supported by the CLI (do it in Terraform, or via the Neutron API if you must). openstack security group rule list --secgroup <name> → invalid (group is positional: openstack security group rule list <name>). openstack project show <p> --column domain → invalid (use domain_id). openstack subnet list --network <name> → needs the network ID, not the name. openstack flavor list / image list work; sort keys like column:updated_at are rejected (use a real column + --sort-ascending).

Read the full file on GitHub · 167 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 1mo ago First seen · 167 lines · 124 tokens per session scan C b2542020c241

Subscribe to this mod's changes

arbutus is a skill published in the GitHub repository ualberta-rcg/drac-agent-skills (2 stars, last pushed 1mo ago), licensed MIT. It adds 124 tokens to every session and 2,955 once invoked, about $0.0005 per session on Opus 5.5. A static security scan graded it C with 1 finding (cloud metadata endpoint). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-10-07.

Related

arbutus compared with skills from other repositories

arbutus next to 6 skills from other repositories
ModTypeStarsLast pushLicenceScanTokensWorks with
arbutusualberta-rcg/drac-agent-skillsSkill21mo agoMITC124Claude Code, Codex
gke-compute-classesgoogle/skillsSkill23kyesterdayApache-2.0A83Claude Code, Codex
gke-reliabilitygoogle/skillsSkill23kyesterdayApache-2.0A85Claude Code, Codex
gke-workload-securitygoogle/skillsSkill23kyesterdayApache-2.0A171Claude Code, Codex
cloud-architectJeffallan/claude-skillsSkill12k8d agoMITA71Claude Code
nemo-automodel-launcher-configNVIDIA/skillsSkill3.9kyesterdayApache-2.0A30Claude Code
azure-mgmt-botservice-dotnetmicrosoft/skillsSkill3.2kyesterdayMITA78Claude Code