6.5 KiB
REMOTE-1453: Tech Spec - Resolve service-account global skills at agent driver startup
Context
The product behavior is defined in specs/REMOTE-1453/PRODUCT.md. This spec covers the client-side runtime implementation for resolving service-account User.globalSkills during Oz agent startup.
Relevant existing pieces:
crates/warp_cli/src/skill.rs:SkillSpec,SkillSpec::from_str,SkillSpec::is_full_path.app/src/ai/skills/file_watchers/skill_watcher.rs: scans repository trees forSKILL.mdfiles.app/src/ai/skills/skill_manager.rs: stores the loaded skills for the active run.app/src/ai/agent_sdk/driver/environment.rs: environment repository clone helper used by environment prep.app/src/ai/cloud_environments/mod.rs:GithubRepo { owner, repo }andAmbientAgentEnvironment.github_repos.app/src/ai/agent_sdk/driver.rs: agent startup sequence, environment prep, and Oz-only repo skill loading.
Implemented approach
1. Global skill parsing helpers
app/src/ai/skills/global_skills.rs owns the reusable parsing and filtering helpers and is re-exported through app/src/ai/skills/mod.rs.
resolve_skill_repos(raw_specs: &[String]) -> (Vec<SkillSpec>, Vec<GithubRepo>)parses raw server strings with the existing CLI parser, logs warn-level parse failures, skips invalid entries, and extracts org-qualified(org, repo)pairs from the parsed specs while preserving first-seen order.filter_skills_by_spec(repo_path, skills, specs)takes the full scan result for one global-only repo and returns only the parsed skills explicitly requested for that repo. Filtering behavior:- Full-path specs match
repo_path.join(spec.skill_identifier)exactly. - Simple-name specs match parsed
ParsedSkill::namevalues and pick the first match by provider-directory precedence. - Duplicate selected paths are collapsed.
2. Driver source classification
app/src/ai/agent_sdk/driver.rs separates global skill resolution from repository skill loading using two explicit async methods rather than a unified load-request type.
GlobalSkillResolutioncarries parsed global specs and cloneable global skill repos.load_environment_skillshandles all repos that are part of the configured environment: it waits forRepoMetadataModelindexing to complete, then scans withSkillWatcher::read_skills_for_reposand loads all discovered skills.load_global_skillshandles global-only repos: it reads directly from the known provider directories on disk viaread_skills_from_directories(noRepoMetadataModeldependency), then appliesfilter_skills_by_specto keep only the explicitly requested skills. Because global skill repos are cloned before environment prep and are not registered withDetectedRepositories, they are not picked up bySkillWatcher'sRepositoryMetadataEventpath;load_global_skillsreads them directly from disk instead. If a repo appears in both the environment and the global skill set,load_environment_skillsruns over it and loads all skills;load_global_skillsmay also process it and add the filtered subset, butSkillManagerdeduplicates by path so the effective result is all skills from that repo.
3. Driver startup sequence
For Oz harnesses, AgentDriver::run_internal now does the following after the session is shared and before environment prep:
- Read cached
AuthStateProvider::get().global_skills(). - Parse specs and resolve cloneable repos with
resolve_skill_repos. - Clone those repos best-effort with
environment::clone_repo(which clones the repo but does NOT register it withDetectedRepositories, so only the explicitly requested global skills are loaded from it). - Prepare the configured environment, if any, preserving the existing file-based MCP discovery and setup-command sequencing. Environment repos are cloned via
ensure_repo_cloned, which both clones and registers withDetectedRepositories. - Call
load_environment_skillswith the environment'sgithub_repos, thenload_global_skillswith the global specs and repos. Global-skill cloning is performed for all harnesses (before the Oz-only guard) so that skills are on disk, but skill loading intoSkillManagerremains Oz-only because third-party harnesses have separate skill systems.
4. Repo skill loading
Skill loading is split into two separate functions instead of a single unified load_skills_from_repos:
load_environment_skills(foreground, repos): waits forRepoMetadataModelindexing on each repo, then scans withSkillWatcher::read_skills_for_reposand loads all discovered skills intoSkillManager.load_global_skills(foreground, specs, repos): reads skills directly from provider directories viaread_skills_from_directories(usingSKILL_PROVIDER_DEFINITIONS), appliesfilter_skills_by_specto keep only explicitly requested skills, and loads the result intoSkillManager. This path does not depend onRepoMetadataModelbecause global-skill repos are not registered withDetectedRepositories. Both functions callSkillManager::set_cloud_environment(true)andhandle_skills_added, preserving the existing in-scope behavior for repo-loaded skills.
Behavior guarantees
- Environment repos continue to autodiscover all skills.
- Global-only repos do not expose unrelated skills from the same repo.
- Environment/global overlap is resolved in favor of environment autodiscovery.
- Clone failures for global-skill repos are warn-and-continue.
- Invalid global skill specs are warn-and-skip.
- Non-cloneable specs do not trigger clone attempts.
Testing and validation
Unit coverage added or expected:
resolve_skill_reposskips invalid specs and handles empty input, unqualified specs, org-qualified specs, and duplicate repos.filter_skills_by_specloads only requested simple-name skills, respects provider precedence, and matches full-path specs. Validation commands:cargo fmt- Targeted
cargo nextestfor theglobal_skillsanddrivertests touched by this change. - A targeted
cargo checkor package build if test compilation exposes broader type issues.
Follow-ups
- Add integration coverage around a real service-account run once the test harness can inject
User.globalSkillsand cloned repo contents cheaply. - Consider refreshing
User.globalSkillsat run start if cached user state can become stale for long-lived clients. - Consider global-skill provenance in skill listing UI or logs if users need to debug why a skill was available.
- Revisit third-party harness behavior if those harnesses adopt the same runtime skill loading path.