Skip to content

[Feature] Project-scoped aliases (.qwik.toml) #39

Description

@ragilhadi

Milestone v1.4 — Teams & scale. Depends on #23, #24, #31.

Summary

Discover a .qwik.toml in the current directory or any ancestor, and layer its aliases over the user store for shells running inside that tree — so a repo can ship its own commands.

Motivation

Every non-trivial project accumulates commands that only make sense inside it: make dev, docker compose -f docker-compose.dev.yml up, a long pytest -k line, a deploy script with six flags. These are exactly the commands worth aliasing and exactly the ones that do not belong in a global, machine-wide store.

This is the pattern direnv, mise, and just have each proven demand for, and qwik is unusually well placed to serve it: the overlay work already established a read-only layered store, and all_aliases() already merges layers with a precedence rule. This is a third layer on machinery that exists.

For teams it is also the natural answer to the onboarding question — a new contributor clones the repo and immediately has the project's commands, with no setup step and nothing to install.

Proposed Design

.qwik.toml, committed to the repo:

version = 1

[aliases.dev]
command = "docker compose -f docker-compose.dev.yml up"
description = "Start the dev stack"

[aliases.t]
command = "pytest -q {@}"

Precedence, highest first: project → user → overlay.

qwik list                     # project aliases marked [project]
qwik project init             # scaffold a .qwik.toml
qwik project trust            # opt in to this directory's aliases
qwik project untrust

Trust is mandatory and explicit. A .qwik.toml arrives by git clone from whoever wrote the repo, so it is untrusted code by definition. Auto-loading it would mean cloning a repo is enough to define commands in a contributor's shell — an unacceptable default. Instead:

  • A newly-seen .qwik.toml is inert until qwik project trust is run in that directory
  • Trust is recorded per absolute path plus a content hash in the user config
  • If the file changes after trusting, it reverts to inert and the user is prompted to review a diff
  • qwik doctor lists trusted project directories

Shell integration needs the hook to re-evaluate on directory change (chpwd in zsh, PROMPT_COMMAND in bash, --on-variable PWD in fish). That is the main implementation risk and should be prototyped before committing to the design.

Implementation Plan

  • qwik/core/project.py — upward discovery from cwd (stopping at $HOME or a filesystem boundary), parse, hash
  • qwik/core/trust.py — trust store at <config_dir>/trusted.toml, path + SHA-256
  • qwik/core/models.pyAliasStore.project_aliases, and all_aliases() precedence
  • qwik/commands/project.pyinit, trust, untrust, list
  • Renderers — a directory-change hook per shell; document the added startup cost, which makes [Bug] qwik init adds ~300 ms to every shell start — prompt_toolkit and pydantic are imported eagerly #31 a hard prerequisite rather than a nice-to-have
  • qwik run, pick, list, search, show — project-layer aware

Acceptance Criteria

  • .qwik.toml is discovered from cwd upward and layered above the user store
  • An untrusted .qwik.toml is never loaded and never executed; qwik list says it exists and how to trust it
  • Trust is per-path and invalidated when the file's hash changes
  • Aliases are marked by layer in list, search, show, and the picker
  • Shell hooks refresh on directory change in bash, zsh, and fish
  • The per-cd cost is measured and documented
  • A project alias shadowing a user alias resolves to the project one, and show reports both
  • qwik doctor lists trusted directories
  • Security tests: cloning a repo with a .qwik.toml defines nothing until trusted

Audit ref F8 · full roadmap in docs/audit/FEATURES.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions