-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Feature : Remote catalogue of constitutions #805
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Adds a remote constitution feature that allows teams to fetch pre-made project constitutions from GitHub repositories during initialization. This enables organizations to maintain centralized, standardized governance principles and development guidelines.
- Adds new CLI command
list-constitutionsfor browsing available constitutions - Extends
initcommand with 5 new options for remote constitution management - Includes comprehensive documentation and example constitution repository templates
Reviewed Changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/specify_cli/init.py | Core implementation with new functions for GitHub API integration and enhanced init command |
| docs/toc.yml | Added navigation entries for remote constitution documentation |
| docs/remote-constitutions.md | Comprehensive guide on setting up and using remote constitutions |
| docs/example-constitutions-repo.md | Example constitution templates and repository structure guide |
| README.md | Updated CLI reference table and usage examples |
| CHANGELOG.md | Documented new feature additions and changes |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| token = _github_token(cli_token) | ||
| return {"Authorization": f"Bearer {token}"} if token else {} | ||
|
|
||
| def fetch_remote_constitutions_list(repo_url: str, branch: str = "main", path: str = "", github_token: str = None) -> list[dict]: |
Copilot
AI
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter github_token should have a consistent type annotation. Use str | None to match the pattern used in _github_auth_headers function.
| def fetch_remote_constitutions_list(repo_url: str, branch: str = "main", path: str = "", github_token: str = None) -> list[dict]: | |
| def fetch_remote_constitutions_list(repo_url: str, branch: str = "main", path: str = "", github_token: str | None = None) -> list[dict]: |
| except Exception as e: | ||
| raise RuntimeError(f"Error fetching constitutions from {owner}/{repo}: {e}") | ||
|
|
||
| def fetch_remote_constitution_content(download_url: str, github_token: str = None) -> str: |
Copilot
AI
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter github_token should have a consistent type annotation. Use str | None to match the pattern used in _github_auth_headers function.
| if branch != "main": | ||
| api_url += f"?ref={branch}" |
Copilot
AI
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition should check if branch is not 'main' OR if there are other query parameters needed. Currently, if branch is 'main' but other parameters exist, the ref parameter won't be added. Consider using proper URL parameter handling.
| repo: str = typer.Argument(..., help="GitHub repository containing constitutions (format: 'owner/repo' or full URL)"), | ||
| path: str = typer.Option("", "--path", help="Path within the repository where constitutions are stored"), | ||
| branch: str = typer.Option("main", "--branch", help="Branch to fetch from"), | ||
| github_token: str = typer.Option(None, "--github-token", help="GitHub token for private repositories"), |
Copilot
AI
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter github_token should have a consistent type annotation. Use str | None to match the pattern used in other functions.
| github_token: str = typer.Option(None, "--github-token", help="GitHub token for private repositories"), | |
| github_token: str | None = typer.Option(None, "--github-token", help="GitHub token for private repositories"), |
| selected_constitution_name = select_with_arrows( | ||
| constitution_choices, | ||
| "Choose a constitution:", | ||
| list(constitution_choices.keys())[0] |
Copilot
AI
Oct 9, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default selection logic list(constitution_choices.keys())[0] could fail if constitutions list is empty. This case is already handled above with the early exit, but consider using constitution_choices.keys() and list(constitution_choices.keys())[0] or similar defensive programming.
| list(constitution_choices.keys())[0] | |
| next(iter(constitution_choices.keys()), None) |
|
@localden Curious on your thoughts here. I feel it would be a positive feature for the project to support a remote catalogue of well crafted constitutions. Please let me know if there is anything you feel needs changing. |
|
@housekelly can we do this as part of #892 |
|
@housekelly Nice one, kudos! I was questioning something like this while needing to switch between constitutions_c & constitution_py, in a Embedded C + Python codebase. How would you manage a sort of constitution tree or principles composition? ( @localden ) I'm seeing that there are couple of layers that arise from multiple constitutions:
So following up with your idea, I was thinking about setting constitutions or principles layers (not sure about the best atomicity) and enable a sort of "pick your poison" workflow in the command. I imagine something like:
What do you think would be the best approach to the issue? |
|
@dasiths happy to update it to support a folder which can include other notable files like your issue suggests. I feel like this functionality (remote repo support) belongs in the core list of cli functions. As to @MadHuslista 's point. I would prefer the tool not be very opinionated on the structure of the remote constitution for this very reason. People will care about team practices, cloud practices, federal steering, etc. If we support a remote repo i had envisioned writing some workflows that would combine those different layers into the final set of constitutions. Let each group of devs worry about their own heirarchy |
|
Good stuff, exactly what our team starting spec-driven has been thinking about (we now have 2 repos frontend/backend) and they need to share a "domain knowledge" constitution. One follow-up idea: the new helpers in init.py (fetch_remote_constitutions_list, fetch_remote_constitution_content, and the CLI wiring) are tightly coupled to the GitHub REST API. If we can carve out a small provider abstraction there (parsing repo URLs, routing to provider-specific fetchers), the same CLI could support for example Azure DevOps repos too—most of the wiring is already done. That would let us reuse the new options in both the init and list-constitutions commands, and mirror the docs updates (remote-constitutions.md, README.md, CHANGELOG) for Azure DevOps usage. Long-term, having that abstraction in place would make it straightforward to plug in additional SCMs down the road (GitLab, Bitbucket, etc.), giving teams more flexibility without revisiting the CLI surfaces again |
| owner, repo = parts[0], parts[1] | ||
|
|
||
| # Construct API URL to list directory contents | ||
| api_url = f"https://api.github.com/repos/{owner}/{repo}/contents/{path}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is a GH project, but could you not hardcode to github. Instead only support fqdn with raw text or tar distributions (tar is less important). And Instead of it being a folder have it be a single file manifest. Similar to openapispec, ideally this model follows standard artifact + cdn distribution thus I get to use those same tools to publish/ manage/ version control.
Example: we use Jfrog arifactory and would like to run our spec through CI/CD and then publish (thus we can security scan, we can have uptime healthchecks, retrieve clear usage, utilize our existing data-rentention policy), this is valuable for us since our developers' rbac is used in flight to hit a zero trust endpoint and only show specs related to their identify, we do a similar thing for packages. Not scope creeping. But rather would like to instead reduce the client side processing speckit is doing. Instead I think add a publish command/ action on github that treats specs like artifacts.
This would flow nicely into other things you do. I personally don't like tis distribution model. Thoughts?
The intention here is to allow support for fetching pre-made constitutions from a remote github repository. It would be beneficial to allow a dev group or company to have well curated constitutions that contain all of the steering guidelines, best practices, and company specifics to allow the specify-cli to read from a remote repo and allow the user to select one, instead of starting from scratch each time.
This feature adds a few new cli arguments to facilitate.
Screenshot in action.

File Modified:
src/specify_cli/__init__.pyNew Functions:
fetch_remote_constitutions_list()- Fetches list of constitutions from GitHubfetch_remote_constitution_content()- Downloads specific constitution contentNew Command:
list-constitutions- Browse available constitutions from a repositoryEnhanced Command:
init- Now supports 5 new options for remote constitutions:--constitution-repo--constitution-name--constitution-path--constitution-branch--constitution-interactive