Skip to content

8.1. License

In one glance

  • You will: Tell which license covers any file you want to reuse, write the attribution line, and run the gate that keeps those licenses honest.
  • You need: mise run install:maintainer finished, so the full license gate can synchronize all six lock-owned dependency profiles.
  • Time: about 16 minutes, reference.

What is an open-source license, briefly?

A license is the legal permission that lets other people use your work. Without one, default copyright reserves all rights, and nobody may legally copy or modify what you publish — even on a public GitHub repo. Open licenses grant those permissions up front. They fall into two broad families:

  • Permissive (e.g., MIT, Apache-2.0): do almost anything, including using the work in closed-source or commercial products, as long as you preserve the copyright and license notice.
  • Copyleft (e.g., GPLv3): the same freedoms, but any derivative you distribute must be released under the same license, keeping it open.

For creative works, Creative Commons plays the same role: CC-BY is the permissive option (attribution only); variants add conditions like NC (non-commercial) or SA (share-alike). This course deliberately chose the most permissive options — MIT and CC-BY — so the material spreads with as little friction as possible.

What license is this course under?

A dual license, because the repository holds two kinds of work that want different, purpose-built grants:

Three things under docs/ are configuration, not prose, and sit outside the CC-BY grant: docs/LICENSE.txt (the Creative Commons text itself), docs/CNAME (the custom-domain record), and docs/stylesheets/ (the site CSS). The bundled Inter and Outfit font files are a separate third-party exception under the SIL Open Font License 1.1; their exact notices travel beside the files.

Both grants allow use, adaptation, redistribution, and commercial reuse. CC-BY requires attribution; MIT requires preservation of its copyright and permission notice. Neither imposes the other's terms — that separation is the whole point of splitting them.

flowchart TD
    F([Any file in the repo]) --> Font{Bundled Inter or Outfit font?}
    Font -->|yes| OFL["OFL-1.1<br/>(docs/assets/fmind/OFL-1.1.txt)"]
    Font -->|no| Q{Course prose under docs/?}
    Q -->|"yes — the chapters"| CC["CC-BY-4.0<br/>(docs/LICENSE.txt)"]
    Q -->|"no — code, scripts, workflows, config,<br/>docs/LICENSE.txt, docs/CNAME, docs/stylesheets/"| MIT["MIT<br/>(root LICENSE + subtree copies)"]

Diagram in words: Check the two bundled font files first; they keep their OFL-1.1 notices. Course prose is CC-BY-4.0, while executable source and site configuration use MIT.

Why two licenses instead of one?

Because prose and software are best served by different, purpose-built licenses:

  • Creative Commons licenses are written for creative and educational works — articles, courses, diagrams, datasets. CC-BY-4.0 is the natural fit for the chapters you are reading.
  • Software licenses like MIT are written for source code — they speak in terms of "the Software", warranties, and liability, which is what you want around the agent and the manifests.

Splitting them keeps each grant clean: reusing a paragraph of the course and forking the agent have clear, separate rules, and neither accidentally imposes the other's terms.

What can I do with the content and the code?

Under CC-BY-4.0 (the course content) you may share and adapt the material, including for commercial use. You must give credit, link the license, and note any changes.

Under MIT (the code) you may use, copy, modify, merge, publish, distribute, sublicense, and sell the software, provided you keep the copyright and permission notice. Both come "as is", with no warranty.

At a glance, what you may do and must do for each asset:

Asset License You may You must
Course prose (docs/) CC-BY-4.0 share, adapt, sell credit author + source, link the license, note changes
Code, infra, scripts, config MIT use, modify, sublicense, sell keep the copyright + permission notice
Inter and Outfit font files OFL-1.1 use, embed, modify, distribute preserve each font's copyright and OFL notice
A rendered page mixing grants CC-BY + MIT reuse the whole page satisfy both grants at once

Copying a page copies two licenses

Copy a rendered chapter and you copy material under two licenses at once. The surrounding explanation is CC-BY, so attribute it; the quoted code block is MIT, so preserve its notice.

Which license covers the code snippets shown in the course?

The chapters are CC-BY, but many of them embed real source code rather than paraphrasing it. The FAQ pages mirror source through pymdownx.snippets: a --8<-- marker pulls a named region out of a file under agents/ straight into the rendered page. The guardrail excerpt on 4.5. Guardrails, for instance, is a live include of a region in agents/python/src/agent/composition.py, rebuilt from the file at every site build. So the code you read in a fenced block is the MIT-licensed source, verbatim, not a CC-BY retelling of it.

That is what makes a rendered page carry two grants at once. In practice:

  • Lifting a snippet into your own project: treat it as MIT source and keep the copyright line.
  • Republishing a whole page: satisfy both grants.

None of this is exotic. It is the ordinary consequence of putting code and prose in one document, and it is easy to miss when you only think of the page as "the course". How the snippet mirroring is wired is owned by 8.4. Documentation.

How do I attribute it?

Both licenses require you to preserve their notice, and CC-BY additionally requires attribution. Keep it simple and visible:

  • Reusing course content (CC-BY-4.0) — credit the author and source, link the license, and indicate if you changed anything. For example:

Adapted from the AgentOps Open Course by Médéric Hurier (MLOps Courses), licensed under CC-BY-4.0. Changes were made.

  • Reusing code (MIT) — keep the LICENSE file (or its copyright line and permission notice) in your copy or derivative. The exact notice to preserve is:

Copyright (c) 2026 Médéric Hurier (Fmind)

That is the whole obligation. You do not need to ask permission, pay a fee, or open-source your own project.

Why does each reusable subtree carry its own LICENSE file?

The root LICENSE is not the only MIT copy. Four byte-identical copies sit beside the independently distributable component trees: agents/LICENSE, clients/LICENSE, infra/LICENSE, and load/LICENSE.

The concept is simple: a license grant travels only with the files a recipient actually receives. If someone vendors or forks agents/ on its own — a realistic way to reuse the reference agent without the docs or the load harness — the root notice never comes along. A LICENSE inside each subtree guarantees the grant is present in every copy that can be split off, so no reusable directory ever ships as bare, all-rights-reserved code.

The repository keeps those copies honest rather than trusting them. The drift gate below runs cmp -s on each of the four files against the root LICENSE and fails on a single-byte difference. The notices cannot silently diverge as the repo evolves.

How does the repository prevent license drift?

A dual license is only as trustworthy as the process that keeps it true while dependencies churn. Two gates enforce it, and they check different things.

mise run check:licenses runs check-licenses.sh, a machine-verifiable gate that does four concrete things:

  1. Layout — confirms LICENSE, docs/LICENSE.txt, and the font OFL file exist; checks both font copyright notices; then cmp -s each of agents/LICENSE, clients/LICENSE, infra/LICENSE, and load/LICENSE against the root and fails on any byte difference.
  2. Inventory — creates isolated temporary environments and collects a pip-licenses manifest for six lock-owned profiles, one at a time: documentation development, agent runtime, agent development, agent evaluation, framework comparison, and MLflow runtime. It then injects one fake proprietary distribution, proves the inventory sees it, resynchronizes from the lock, and requires the clean and pre-populated inventory verdicts to be byte-identical.
  3. Allowlist — rejects any dependency whose reported License is not on an explicit allowlist of permissive and weak-copyleft identifiers (MIT, Apache-2.0, BSD, ISC, MPL-2.0, PSF, and their SPDX combinations). Weak-copyleft means the share-alike duty covers only the files you modify; SPDX is the standard short-code vocabulary for license names.
  4. Embedded text — for the handful of packages whose metadata reports UNKNOWN (huey, skops, and google-crc32c), it does not wave them through; it reads the embedded LicenseText and asserts it matches the expected license (Permission is hereby granted for huey, MIT License for skops, Apache License for google-crc32c).
flowchart TD
    A["mise run check:licenses"] --> B["verify MIT/CC license files,<br/>font OFL notices, and subtree copies"]
    B --> C["sync 6 lock-owned profiles:<br/>docs dev · agent runtime/dev/eval/comparison · MLflow runtime"]
    C --> C1["inject an observable ambient package,<br/>exact-sync again, compare with clean inventory"]
    C1 --> C2["inventory each isolated environment<br/>with pip-licenses"]
    C2 --> D{"every package License<br/>on the allowlist?"}
    D -->|no| F([fail: unapproved license])
    D -->|"yes, except UNKNOWN packages"| E["verify embedded LICENSE text<br/>(huey · skops · google-crc32c)"]
    E -->|missing| F
    E -->|verified| G([pass])

Diagram in words: The full gate checks repository notices, synchronizes six isolated profiles, proves a pre-populated environment returns to the clean inventory, rejects unapproved licenses, and verifies reviewed embedded license text.

Run the full maintainer gate yourself:

mise run check:licenses

mise run check:licenses:core is the smaller learner path: documentation development plus agent runtime and development. The full command adds agent evaluation, framework comparison, and MLflow runtime. Each profile is synchronized into a fresh temporary environment from its lock. The deliberate agentops-ambient-contaminant fixture makes that isolation an executed regression, so an optional package left in a workstation venv cannot change the verdict. A cold machine may still download missing locked wheels.

A full pass prints the layout line, a lock-synchronization digest and package count for each profile, then one embedded license verified line per reviewed package whose metadata alone is insufficient. Each temporary environment is removed after its inventories are captured, so peak disk use is bounded by one profile. Counts and digests are runtime evidence, not prose constants:

repository licenses: MIT software + CC BY 4.0 course content + OFL 1.1 fonts
documentation dependencies: lock-synchronized development profile (<sha256>)
documentation dependencies: clean and pre-populated inventory verdicts are identical
documentation dependencies: <N> packages use reviewed open-source licenses
agent runtime dependencies: lock-synchronized runtime profile (<sha256>)
agent runtime dependencies: <N> packages use reviewed open-source licenses
agent development dependencies: lock-synchronized development profile (<sha256>)
agent development dependencies: <N> packages use reviewed open-source licenses
agent evaluation dependencies: lock-synchronized evaluation profile (<sha256>)
agent evaluation dependencies: <N> packages use reviewed open-source licenses
MLflow runtime dependencies: lock-synchronized runtime profile (<sha256>)
MLflow dependencies: <N> packages use reviewed open-source licenses
agent development: embedded license verified for google-crc32c
agent evaluation: embedded license verified for huey
agent evaluation: embedded license verified for skops
MLflow: embedded license verified for google-crc32c
MLflow: embedded license verified for huey
MLflow: embedded license verified for skops

Each <N> is the total package count for one isolated profile. The embedded license verified lines cover huey, skops, and google-crc32c, whose bundled license text is confirmed instead of waved through. A single unapproved identifier, missing embedded notice, or failed lock synchronization exits non-zero, so this is a merge gate rather than an ambient-environment report.

What a failure looks like

Add a dependency whose license is not on the allowlist and the gate names the environment, the package, and the license it reported, then exits non-zero:

agent dependencies have unapproved license metadata:
<package> <version>: <license>

A package whose embedded text cannot be confirmed fails the same way, printing agent: could not verify the embedded license for <package>.

The second gate is Trivy, which reads the same trivy.yaml policy wherever it runs: over the working tree locally, and over the built container images in CI. It reaches the OS-level packages that a Python inventory never sees. A scanner is evidence, not a legal opinion: review any new dependency and its upstream license before adding it.

Deeper: how the container scan complements this gate

mise run secure complements that policy with Trivy's dependency, secret, misconfiguration, and license scanners plus a full-history gitleaks scan. Trivy classifies copyleft as HIGH "restricted" risk, so its license gate runs at UNKNOWN/HIGH/CRITICAL and explicitly accepts only the reviewed runtime identifiers listed in trivy.yaml — the GPL/LGPL used by the Wolfi/Python base image, a few valid SPDX expressions, legacy metadata labels, and public-domain grants Trivy leaves unclassified — while still rejecting non-commercial and every other unreviewed term.

That same trivy.yaml policy is reused wherever images are built. The scan.yml container matrix builds the agent and MLflow images and runs Trivy twice on each — vulnerabilities and secrets at HIGH/CRITICAL, then licenses at UNKNOWN/HIGH/CRITICAL — and the release workflow applies the identical license gate before any image is pushed or published (see 8.2. Releases). The two gates are complementary by design: check-licenses.sh reads the three locked Python environments where the course adds most of its dependencies, while the Trivy image scan reaches the OS-level packages baked into each container that a Python inventory never sees.

What license should my own agent use?

When you turn the reference agent into your own project (see 8.3. Templates), pick the license that matches your goal:

  • Want the widest possible reuse with minimal strings? Use MIT, as this repository's code does.
  • Need an explicit patent grant for contributors? Use Apache-2.0.
  • Want derivatives to stay open? Use a copyleft license like GPLv3.

Use choosealicense.com to decide, then drop the full, unmodified license text into a LICENSE file at your repo root. Remember that your project is a derivative work of its dependencies: it builds on code someone else licensed to you. Check that their licenses are compatible with the one you pick.

How do I cite this course?

The repository ships CITATION.cff, a machine-readable citation file understood by GitHub and reference managers such as Zotero. On GitHub, open the repository's Cite this repository menu to export the current metadata.

The file records type: software, the current version, and a license list that names both MIT and CC-BY-4.0. The citation metadata therefore mirrors the dual license rather than flattening it to one.

Citation and licensing solve different problems: the CFF file gives readers a consistent scholarly reference, while CC-BY-4.0 and MIT define the legal permissions and attribution obligations for reuse.

What proves this page worked?

Run the gate once more and read its output line by line:

mise run check:licenses

Then answer two questions without scrolling up: which license covers agents/python/src/agent/tools.py, and which one covers the page you are reading.

You are done when:

  • mise run check:licenses prints repository licenses: MIT software + CC BY 4.0 course content + OFL 1.1 fonts, then the inventory and package-count lines for all five profiles, and exits zero.
  • You can say from memory that agents/python/src/agent/tools.py is MIT and that this page is CC-BY-4.0.
  • You can write the CC-BY attribution line for a chapter you adapted, including the note that changes were made.
  • You can explain why agents/LICENSE exists even though the repository root already carries one.

Return to 8. Community and pick your next maintenance question when you can name the license of any file in this repository from its path alone.