Ganzua Manual
Quick Links: GitHub | PyPI | CLI Reference
Ganzua is tool for picking dependency information from Python lockfiles,
and manipulating the version constraints in pyproject.toml files.
For example, we can summarize the differences between two uv.lock files.
Ganzua is designed for scripting, so by default we get JSON output:
$ ganzua diff corpus/old-uv-project corpus/new-uv-project
{
"stat": {
"total": 2,
"added": 1,
"removed": 0,
"updated": 1
},
"packages": {
"annotated-types": {
"old": null,
"new": {
"version": "0.7.0",
"source": "pypi"
}
},
"typing-extensions": {
"old": {
"version": "3.10.0.2",
"source": "pypi"
},
"new": {
"version": "4.14.1",
"source": "pypi"
},
"is_major_change": true
}
}
}
We can also opt in to Markdown (GFM) output, which will produce a summary and a table:
$ ganzua diff --format=markdown corpus/old-uv-project corpus/new-uv-project
2 changed packages (1 added, 1 updated)
| package | old | new | notes |
|-------------------|----------|--------|-------|
| annotated-types | - | 0.7.0 | |
| typing-extensions | 3.10.0.2 | 4.14.1 | (M) |
* (M) major change
Aside from inspecting or diffing lockfiles,
we can extract and manipulate constraints from pyproject.toml files:
$ ganzua constraints inspect --format=markdown corpus/new-uv-project/pyproject.toml
| package | version |
|-------------------|---------|
| annotated-types | >=0.7.0 |
| typing-extensions | >=4 |
For more examples and further background, see the announcement blog post.
What makes Ganzua special?
Ganzua is not a general-purpose tool.
It's focused solely on working with two modern Python project managers, uv and Poetry, and their native lockfile formats. In particular, there's no support for requirements.txt.
Ganzua strives to be complete, compliant, and correct. Ganzua is 0% AI and 100% human expertise, informed by reading the relevant PEPs, docs, and the source code of relevant tools. The tool is thoroughly tested with 100% branch coverage, and has seen extensive use in large-scale real-world projects. Ganzua is intentionally stupid and avoids dangerous stuff like editing lockfiles or interacting with Git.
Ganzua is designed for scripting. All subcommands are designed for JSON output first, with output that conforms to a stable schema. Where appropriate, Ganzua offers an optional Markdown view on the same data, which lets scripts generate human-readable summaries. Ganzua does not offer GitHub Actions, but it's really easy to integrate Ganzua into your CI workflows.
Next Steps
Continue reading the installation guide or the command line reference.
Installation
Ganzua is available on PyPI: https://pypi.org/project/ganzua/
Recommended: run or install via the uv package manager:
uvx ganzuato try Ganzua without installationuv tool install ganzuato install Ganzua on your machine
Alternative: run or install via the pipx tool:
pipx run ganzuato try Ganzua without installationpipx install ganzuato install Ganzua on your machine
When invoking Ganzua in scripts or in a CI job, consider pinning or constraining a version. This prevents your scripts from breaking when Ganzua has an incompatible change. For example:
uvx ganzua==0.3.0to pin an exact versionuvx 'ganzua>=0.3.0,<0.4.0'to constraint to a version range (remember quotes to escape special characters like<)
To preview a bleeding-edge version without waiting for a PyPI release, you can install directly from the Ganzua repository on GitHub. For example:
uvx git+https://github.com/latk/ganzua.gitpipx run --spec git+https://github.com/latk/ganzua.git ganzua
Do not add Ganzua as a dependency to your project, instead prefer invoking Ganzua via uvx or pipx run.
You can technically install Ganzua into an existing venv using tools like uv, Poetry, or Pip.
But since Ganzua might require conflicting dependencies, and might even need a different Python version, this is likely to cause more problems than it solves.
Command Line Reference
This section documents all Ganzua subcommands.
ganzuaInspect Python dependency lockfiles (uv and Poetry).ganzua helpShow help for the application or a specific subcommand.ganzua inspectInspect a lockfile.ganzua diffCompare two lockfiles.ganzua constraintsWork withpyproject.tomlconstraints.ganzua constraints inspectList all constraints in thepyproject.tomlfile.ganzua constraints bumpUpdatepyproject.tomldependency constraints to match the lockfile.ganzua constraints resetRemove or relax any dependency version constraints from thepyproject.toml.
ganzua schemaShow the JSON schema for the output of the given command.
ganzua
Usage: ganzua [OPTIONS] COMMAND [ARGS]...
Inspect Python dependency lockfiles (uv and Poetry).
Options:
--helpShow this help message and exit.
Commands:
helpShow help for the application or a specific subcommand.inspectInspect a lockfile.diffCompare two lockfiles.constraintsWork withpyproject.tomlconstraints.schemaShow the JSON schema for the output of the given command.
For more information, see the Ganzua website at "https://github.com/latk/ganzua".
Ganzua is licensed under the Apache-2.0 license.
ganzua help
Usage: ganzua help [OPTIONS] [SUBCOMMAND]...
Show help for the application or a specific subcommand.
Options:
--allAlso show help for all subcommands.--markdownOutput help in Markdown format.
ganzua inspect
Usage: ganzua inspect [OPTIONS] [LOCKFILE]
Inspect a lockfile.
The LOCKFILE should point to an uv.lock or poetry.lock file,
or to a directory containing such a file.
If this argument is not specified,
the one in the current working directory will be used.
Options:
--format [json|markdown]Choose the output format, e.g. Markdown. [default: json]--helpShow this help message and exit.
Examples
We can load various example lockfiles:
$ ganzua inspect corpus/old-uv-project
{
"packages": {
"example": {
"version": "0.1.0",
"source": {
"direct": "."
}
},
"typing-extensions": {
"version": "3.10.0.2",
"source": "pypi"
}
}
}
$ ganzua inspect corpus/new-uv-project
{
"packages": {
"annotated-types": {
"version": "0.7.0",
"source": "pypi"
},
"example": {
"version": "0.1.0",
"source": {
"direct": "."
}
},
"typing-extensions": {
"version": "4.14.1",
"source": "pypi"
}
}
}
$ ganzua inspect corpus/old-poetry-project
{
"packages": {
"typing-extensions": {
"version": "3.10.0.2",
"source": "default"
}
}
}
$ ganzua inspect corpus/new-poetry-project
{
"packages": {
"annotated-types": {
"version": "0.7.0",
"source": "default"
},
"typing-extensions": {
"version": "4.14.1",
"source": "default"
}
}
}
Instead of producing JSON output, we can summarize lockfiles as Markdown:
$ ganzua inspect corpus/old-uv-project --format=markdown
| package | version |
|-------------------|----------|
| example | 0.1.0 |
| typing-extensions | 3.10.0.2 |
The input paths may point to directories or lockfiles. The following invocations are all equivalent:
$ ganzua inspect corpus/new-uv-project$ ganzua inspect corpus/new-uv-project/uv.lock
output for the above commands
{
"packages": {
"annotated-types": {
"version": "0.7.0",
"source": "pypi"
},
"example": {
"version": "0.1.0",
"source": {
"direct": "."
}
},
"typing-extensions": {
"version": "4.14.1",
"source": "pypi"
}
}
}
It is possible for a locked package to have no version
(see issue #4).
In this case, Ganzua will use the pseudo-version 0+undefined:
$ ganzua inspect corpus/setuptools-dynamic-version
{
"packages": {
"setuptools-dynamic-version": {
"version": "0+undefined",
"source": {
"direct": "."
}
}
}
}
JSON Schema
Download: schema.inspect.json
Properties:
packages: map(string → LockedPackage)
type LockedPackage
Properties:
version: stringsource:pypi|default|other| SourceRegistry | SourceDirect
type SourceRegistry
The package is sourced from a third party registry.
Properties:
registry: string
URL or path to the registry.
type SourceDirect
The package is sourced from a specific URL or path, e.g. a Git repo or workspace path.
Properties:
direct: string
URL or path to the package (directory or archive).subdirectory?: string | null
Only allowed if the source points to an archive file.
ganzua diff
Usage: ganzua diff [OPTIONS] OLD NEW
Compare two lockfiles.
The OLD and NEW arguments must each point to an uv.lock or poetry.lock file,
or to a directory containing such a file.
There is no direct support for comparing a file across Git commits,
but it's possible to retrieve other versions via git show.
Here is an example using a Bash redirect to show non-committed changes in a lockfile:
ganzua diff <(git show HEAD:uv.lock) uv.lock
Options:
--format [json|markdown]Choose the output format, e.g. Markdown. [default: json]--helpShow this help message and exit.
Examples
Can show JSON diffs:
$ ganzua diff corpus/old-uv-project corpus/new-uv-project
{
"stat": {
"total": 2,
"added": 1,
"removed": 0,
"updated": 1
},
"packages": {
"annotated-types": {
"old": null,
"new": {
"version": "0.7.0",
"source": "pypi"
}
},
"typing-extensions": {
"old": {
"version": "3.10.0.2",
"source": "pypi"
},
"new": {
"version": "4.14.1",
"source": "pypi"
},
"is_major_change": true
}
}
}
Can also show the diff as Markdown:
$ ganzua diff corpus/old-uv-project corpus/new-uv-project --format=markdown
2 changed packages (1 added, 1 updated)
| package | old | new | notes |
|-------------------|----------|--------|-------|
| annotated-types | - | 0.7.0 | |
| typing-extensions | 3.10.0.2 | 4.14.1 | (M) |
* (M) major change
Here's the same diff in reverse, which now shows a (D) downgrade notice:
$ ganzua diff corpus/new-uv-project corpus/old-uv-project --format=markdown
2 changed packages (1 updated, 1 removed)
| package | old | new | notes |
|-------------------|--------|----------|---------|
| annotated-types | 0.7.0 | - | |
| typing-extensions | 4.14.1 | 3.10.0.2 | (M) (D) |
* (M) major change
* (D) downgrade
Test cases for demonstrating how the (M)/is_major_change note works:
| package | old | new | notes |
|---|---|---|---|
| epoch-changed | 1.2.3 | 1!1.2.3 | (M) |
| epoch-zero | 1.2.3 | 0!1.2.3 | |
| existence-added | - | 1.2.3 | |
| existence-removed | 1.2.3 | - | |
| major | 1.2.3 | 2.1.0 | (M) |
| minor | 1.2.3 | 1.3.4 | |
| validity-invalid-to-invalid | foo | bar | (M) |
| validity-invalid-to-valid | foo | 1.2.3 | (M) |
| validity-valid-to-invalid | 1.2.3 | foo | (M) |
| zerover-change | 0.1.2 | 0.2.0 | (M) |
| zerover-same | 0.1.2 | 0.1.3 |
Test cases for demonstrating how the (D)/is_downgrade note works:
| package | old | new | notes |
|---|---|---|---|
| downgrade | 1.3.4 | 1.0.1 | (D) |
| upgrade | 1.0.1 | 1.3.4 |
The Markdown diff can show notices when the source of a package changes. When multiple entries have the same note, their IDs are deduplicated:
$ ganzua diff corpus/sources-poetry corpus/sources-uv --format=markdown
6 changed packages (1 added, 5 updated)
| package | old | new | notes |
|--------------------|-------|-------|-------|
| click | 8.3.0 | 8.3.0 | (S1) |
| click-example-repo | 1.0.0 | 1.0.0 | (S2) |
| colorama | 0.4.6 | 0.4.6 | (S1) |
| idna | 3.11 | 3.11 | (S1) |
| propcache | 0.4.1 | 0.4.1 | (S1) |
| sources-uv | - | 0.1.0 | |
* (S1) source changed from default to pypi
* (S2) source changed from <git+https://github.com/pallets/click.git@309ce9178707e1efaf994f191d062edbdffd5ce6#subdirectory=examples/repo> to <git+https://github.com/pallets/click.git@f67abc6fe7dd3d878879a4f004866bf5acefa9b4#subdirectory=examples/repo>
If there are no notes, the entire column is omitted:
$ ganzua diff --format=markdown corpus/new-uv-project corpus/minor-uv-project
1 changed packages (1 updated)
| package | old | new |
|-------------------|--------|--------|
| typing-extensions | 4.14.1 | 4.15.0 |
When a there are no changes, only the summary is shown. The Markdown output omits the table:
$ ganzua diff corpus/new-uv-project corpus/new-uv-project
{
"stat": {
"total": 0,
"added": 0,
"removed": 0,
"updated": 0
},
"packages": {}
}
$ ganzua diff corpus/new-uv-project corpus/new-uv-project --format=markdown
0 changed packages
The input paths may point to directories or lockfiles. The following invocations are all equivalent:
$ ganzua diff corpus/old-uv-project corpus/new-uv-project$ ganzua diff corpus/old-uv-project corpus/new-uv-project/uv.lock$ ganzua diff corpus/old-uv-project/uv.lock corpus/new-uv-project$ ganzua diff corpus/old-uv-project/uv.lock corpus/new-uv-project/uv.lock
output for the above commands
{
"stat": {
"total": 2,
"added": 1,
"removed": 0,
"updated": 1
},
"packages": {
"annotated-types": {
"old": null,
"new": {
"version": "0.7.0",
"source": "pypi"
}
},
"typing-extensions": {
"old": {
"version": "3.10.0.2",
"source": "pypi"
},
"new": {
"version": "4.14.1",
"source": "pypi"
},
"is_major_change": true
}
}
}
JSON Schema
Download: schema.diff.json
Properties:
type DiffStat
Properties:
total: intadded: intremoved: intupdated: int
type DiffEntry
Properties:
-
old: LockedPackage | null -
new: LockedPackage | null -
is_major_change?: bool
True if there was a major version change.This doesn't literally mean "the SemVer-major version component changed", but is intended to highlight version changes that are likely to have breakage.
-
is_downgrade?: bool
True if the version was downgraded. -
is_source_change?: bool
True if the package source changed.
type LockedPackage
Properties:
version: stringsource:pypi|default|other| SourceRegistry | SourceDirect
type SourceRegistry
The package is sourced from a third party registry.
Properties:
registry: string
URL or path to the registry.
type SourceDirect
The package is sourced from a specific URL or path, e.g. a Git repo or workspace path.
Properties:
direct: string
URL or path to the package (directory or archive).subdirectory?: string | null
Only allowed if the source points to an archive file.
ganzua constraints
Usage: ganzua constraints [OPTIONS] COMMAND [ARGS]...
Work with pyproject.toml constraints.
Options:
--helpShow this help message and exit.
Commands:
inspectList all constraints in thepyproject.tomlfile.bumpUpdatepyproject.tomldependency constraints to match the lockfile.resetRemove or relax any dependency version constraints from thepyproject.toml.
ganzua constraints inspect
Usage: ganzua constraints inspect [OPTIONS] [PYPROJECT]
List all constraints in the pyproject.toml file.
The PYPROJECT argument should point to a pyproject.toml file,
or to a directory containing such a file.
If this argument is not specified,
the one in the current working directory will be used.
Options:
--format [json|markdown]Choose the output format, e.g. Markdown. [default: json]--helpShow this help message and exit.
Examples
Can inspect the constraints of a pyproject.toml file as JSON or Markdown:
$ ganzua constraints inspect corpus/new-uv-project
{
"requirements": [
{
"name": "annotated-types",
"specifier": ">=0.7.0"
},
{
"name": "typing-extensions",
"specifier": ">=4"
}
]
}
$ ganzua constraints inspect corpus/new-uv-project --format=markdown
| package | version |
|-------------------|---------|
| annotated-types | >=0.7.0 |
| typing-extensions | >=4 |
The same package can appear in multiple constraints, in particular:
- in different extras:
[package.optional-dependencies],[tool.poetry.extras] - in different groups:
[dependency-groups],[tool.poetry.group.*.dependencies]
Due to inheritance mechanisms like {include-group = "…"}, the same constraint can appear in multiple extras (Poetry only) and multiple groups (all flavors).
Here are some examples of how the Ganzua output looks in these cases:
$ ganzua constraints inspect corpus/poetry-multiple-groups
{
"requirements": [
{
"name": "annotated-types",
"specifier": ">=0.7.0"
},
{
"name": "annotated-types",
"specifier": "<0.8.0",
"in_groups": [
"dev",
"types"
]
},
{
"name": "typing-extensions",
"specifier": "<5.0.0,>=4.15.0",
"in_groups": [
"types"
]
},
{
"name": "typing-extensions",
"specifier": "^4.15",
"in_extras": [
"dev",
"types"
]
}
]
}
$ ganzua constraints inspect corpus/poetry-multiple-groups --format=markdown
| package | version | group/extra |
|-------------------|-----------------|----------------------------|
| annotated-types | <0.8.0 | group `dev`, group `types` |
| annotated-types | >=0.7.0 | |
| typing-extensions | <5.0.0,>=4.15.0 | group `types` |
| typing-extensions | ^4.15 | extra `dev`, extra `types` |
JSON Schema
Download: schema.constraints-inspect.json
Properties:
requirements: array(Requirement)
type Requirement
A resolver-agnostic Requirement model.
This corresponds to one dependency entry in a pyproject.toml file.
This is a lexical/textual concept about information in the file,
intended for inspection and edits.
Requirements can be difficult to interpret.
There might be multiple Requirements that point to the same package,
potentially with complementary or contradictory contents.
Features like [dependency-groups] or [tool.poetry.extras]
can include the same Requirement in multiple places,
which is why the in_groups and in_extras fields may have multiple values.
Properties:
-
name: string
The name of the required package. -
specifier: string
Version specifier for the required package, may use PEP-508 or Poetry syntax. -
extras?: array(string)
Extras enabled for the required package. -
marker?: string
Environment marker expression describing when this requirement should be installed. -
in_groups?: array(string)
Dependency groups that this requirement is part of. -
in_extras?: array(string)
Extras that this optional requirement is part of.Requirements can only be part of one extra (with some exceptions).
The
groupsandin_extrasfields are effectively mutually exclusive.Special cases for legacy Poetry:
- When using
[tool.poetry.extras], one requirement can be part of multiple extras. - The
markermight also reference extras.
- When using
ganzua constraints bump
Usage: ganzua constraints bump [OPTIONS] [PYPROJECT]
Update pyproject.toml dependency constraints to match the lockfile.
Of course, the lockfile should always be a valid solution for the constraints. But often, the constraints are somewhat relaxed. This tool will increment the constraints to match the currently locked versions. Specifically, the locked version becomes a lower bound for the constraint.
This tool will try to be as granular as the original constraint.
For example, given the old constraint foo>=3.5 and the new version 4.7.2,
the constraint would be updated to foo>=4.7.
The PYPROJECT argument should point to a pyproject.toml file,
or to a directory containing such a file.
If this argument is not specified,
the one in the current working directory will be used.
Options:
--lockfile PATHWhere to load versions from. Inferred if possible.- file: use the path as the lockfile
- directory: use the lockfile in that directory
- default: use the lockfile in the
PYPROJECTdirectory
--backup PATHStore a backup in this file.--helpShow this help message and exit.
ganzua constraints reset
Usage: ganzua constraints reset [OPTIONS] [PYPROJECT]
Remove or relax any dependency version constraints from the pyproject.toml.
This can be useful for allowing uv/Poetry to update to the most recent versions, ignoring the previous constraints. Approximate recipe:
ganzua constraints reset --to=minimum --backup=pyproject.toml.bak
uv lock --upgrade # perform the upgrade
mv pyproject.toml.bak pyproject.toml # restore old constraints
ganzua constraints bump
uv lock
The PYPROJECT argument should point to a pyproject.toml file,
or to a directory containing such a file.
If this argument is not specified,
the one in the current working directory will be used.
Options:
--backup PATHStore a backup in this file.--to [none|minimum]How to reset constraints.none(default): remove all constraintsminimum: set constraints to the currently locked minimum, removing upper bounds
--lockfile PATHWhere to load current versions from (for--to=minimum). Inferred if possible.- file: use the path as the lockfile
- directory: use the lockfile in that directory
- default: use the lockfile in the
PYPROJECTdirectory
--helpShow this help message and exit.
ganzua schema
Usage: ganzua schema [OPTIONS] {inspect|diff|constraints-inspect}
Show the JSON schema for the output of the given command.
Options:
--format [json|markdown]Choose the output format, e.g. Markdown. [default: json]--helpShow this help message and exit.
Changelog
Unreleased
Breaking changes:
- Schema change for
ganzua constraints inspect:groupswas renamed toin_groups.
New features:
- Greatly improved docs and a new website at https://ganzua.latk.de.
- Track information about extras (optional dependencies) when inspecting constraints.
- Show information about groups and extras in
ganzua constraints inspectMarkdown output.
Fixes:
- Sets are now shown in JSON output as sorted arrays.
Other:
- Rewrote test suite to prefer CLI-level end-to-end tests over unit tests.
Full diff: https://github.com/latk/ganzua/compare/v0.3.0...HEAD
v0.3.0 (2025-11-24)
This release focuses on extracting information about package sources, but also includes quality-of-life improvements and bug fixes. There are no breaking changes.
New features:
- Arguments for
pyproject.tomland lockfile paths are automatically inferred in the common cases where Ganzua is invoked from the project root. Instead of writing full paths, it is also sufficient to point to a directory containing these files. For example,ganzua inspect,ganzua inspect .andganzua inspect uv.lockare generally equivalent. - Keep some information about package sources (PyPI, Git, path dependencies, …) when inspecting lockfiles.
- Indicate certain kinds of differences that might need special attention in diff output (JSON/Markdown):
is_major_change(M),is_downgrade(D),is_source_change(S).
Fixes:
- (https://github.com/latk/ganzua/issues/3) Normalize names of packages, extras, and dependency groups when loading
pyproject.tomlfiles, as required by the packaging specifications. - (https://github.com/latk/ganzua/issues/4) Handle packages without versions in
uv.lockfiles. The fake version0+undefinedwill be substituted instead.
Other:
- Run tests under Python 3.14.
- Added a
CHANGELOG.mdfile. - Various internal changes and testing improvements.
Full diff: https://github.com/latk/ganzua/compare/v0.2.0...v0.3.0
v0.2.0 (2025-09-11)
This release fixes some bugs that were found through real-world usage, adds convenience features like diff summaries, and implements new constraint edits.
Breaking changes:
- Renamed
ganzua constraints removetoganzua constraints reset. - Schema change for
ganzua diffJSON output: diff is nested underpackageskey. - Schema change for
ganzua inspectJSON output: data is nested underpackageskey to match the diff schema.
New features:
- New command
ganzua constraints inspectlists all constraints in apyproject.tomlfile, including extras, environment markers, and dependency groups. This is particularly helpful for debugging Ganzua. - New option
ganzua constraints reset --to=minimumedits constraints to require at least the currently locked version, while removing any previous constraints. Essentially, this makes all direct dependencies upgradeable. - (https://github.com/latk/ganzua/issues/2) Add a summary line to
ganzua diffMarkdown output that counts the number of changes. - Add a
statsection toganzua diffJSON output that counts the number of changes.
Fixes:
- Support loading lockfiles regardless of name. Previously, lockfiles had to be named
poetry.lockoruv.lock. - (https://github.com/latk/ganzua/issues/1) Support
pyproject.tomlfiles with out-of-order tables.
Other:
- Various internal changes. Improvements to
pyproject.tomlmanipulation. Fewer special cases for Poetry.
Full diff: https://github.com/latk/ganzua/compare/v0.1.0...v0.2.0
v0.1.0 (2025-08-16)
Initial release.
- add
ganzua inspect - add
ganzua diff - add
ganzua constraints bump - add
ganzua constraints remove
Support
Ganzua is Open Source software, provided to you free of charge and on an "as is" basis. You are not entitled to support, help, or bugfixes of any kind.
Nevertheless, the Ganzua project may occasionally offer help.
- If you have questions about using Ganzua, you may search existing posts at https://github.com/latk/ganzua/discussions and start a new discussion if necessary.
- If you have discovered a bug in Ganzua, please report it at https://github.com/latk/ganzua/issues.
Ganzua intends to maintain a backwards-compatible command line interface, and intends to use SemVer version numbers.
Only those parts of the CLI that are relevant for scripting are covered by this stability policy:
- commands that inspect or modify files
- machine-readable output, e.g. the schema of JSON output
For example, Ganzua might increment the "minor" version number if a new field is added to JSON output or if new command line options are added, and increment the "major" version if output fields are removed or new required command line arguments are added.
Out of scope are:
- interacting with the
ganzuaPython module - Python versions or dependency versions used by Ganzua
- formatting of human-readable output (e.g. Markdown)
- formatting of error messages
- commands and flags that relate to help messages
License
Copyright 2025 Lukas Atkinson
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.