{"id":13547424,"url":"https://github.com/googlecodelabs/tools","last_synced_at":"2026-01-30T14:59:55.912Z","repository":{"id":39499596,"uuid":"50182994","full_name":"googlecodelabs/tools","owner":"googlecodelabs","description":"Codelabs management \u0026 hosting tools","archived":false,"fork":false,"pushed_at":"2025-07-18T17:35:26.000Z","size":76812,"stargazers_count":4476,"open_issues_count":249,"forks_count":1235,"subscribers_count":258,"default_branch":"main","last_synced_at":"2025-09-08T23:20:00.586Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/googlecodelabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2016-01-22T13:28:44.000Z","updated_at":"2025-09-08T14:12:15.000Z","dependencies_parsed_at":"2023-01-24T12:16:07.250Z","dependency_job_id":"9f3027be-f6d9-4389-a999-3a59375db7fa","html_url":"https://github.com/googlecodelabs/tools","commit_stats":{"total_commits":822,"total_committers":56,"mean_commits":"14.678571428571429","dds":0.6447688564476886,"last_synced_commit":"9f2b585333fc582b0a545f6b4bee0f4466ef71c7"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/googlecodelabs/tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/googlecodelabs%2Ftools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/googlecodelabs%2Ftools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/googlecodelabs%2Ftools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/googlecodelabs%2Ftools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/googlecodelabs","download_url":"https://codeload.github.com/googlecodelabs/tools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/googlecodelabs%2Ftools/sbom","scorecard":{"id":439996,"data":{"date":"2025-08-11","repo":{"name":"github.com/googlecodelabs/tools","commit":"873fe39d02dcbd43005a5c44f6310595d6d9aa3e"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.1,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":10,"reason":"all changesets reviewed","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/go.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v2.2.6 not signed: https://api.github.com/repos/googlecodelabs/tools/releases/108775926","Warn: release artifact v2.2.5 not signed: https://api.github.com/repos/googlecodelabs/tools/releases/82661012","Warn: release artifact v2.2.4 not signed: https://api.github.com/repos/googlecodelabs/tools/releases/36820029","Warn: release artifact v2.2.6 does not have provenance: https://api.github.com/repos/googlecodelabs/tools/releases/108775926","Warn: release artifact v2.2.5 does not have provenance: https://api.github.com/repos/googlecodelabs/tools/releases/82661012","Warn: release artifact v2.2.4 does not have provenance: https://api.github.com/repos/googlecodelabs/tools/releases/36820029"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":10,"reason":"all dependencies are pinned","details":["Info:   2 out of   2 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":0,"reason":"12 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0288","Warn: Project is vulnerable to: GO-2022-0969 / GHSA-69cg-p879-7622","Warn: Project is vulnerable to: GO-2022-1144 / GHSA-xrjj-mj9h-534m","Warn: Project is vulnerable to: GO-2023-1571 / GHSA-vvpx-j8f3-3w6h","Warn: Project is vulnerable to: GO-2023-1988 / GHSA-2wrh-6pvc-2jm9","Warn: Project is vulnerable to: GO-2023-2102 / GHSA-4374-p667-p6c8","Warn: Project is vulnerable to: GHSA-qppj-fm5r-hxr3","Warn: Project is vulnerable to: GO-2024-2687 / GHSA-4v7x-pqxf-cx7m","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw","Warn: Project is vulnerable to: GO-2025-3488 / GHSA-6v2p-p543-phr9"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T05:23:58.237Z","repository_id":39499596,"created_at":"2025-08-19T05:23:58.237Z","updated_at":"2025-08-19T05:23:58.237Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28914895,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T12:13:43.263Z","status":"ssl_error","status_checked_at":"2026-01-30T12:13:22.389Z","response_time":66,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T12:00:55.337Z","updated_at":"2026-01-30T14:59:55.877Z","avatar_url":"https://github.com/googlecodelabs.png","language":"Go","readme":"# Tools for authoring and serving codelabs\n\nCodelabs are interactive instructional tutorials, which can be authored in Google Docs\nusing some simple formatting conventions. You can also author codelabs using markdown syntax.\nThis repo contains all the tools and documentation you’ll need for building and publishing\nyour own codelabs.\n\nIf you're interested in authoring codelabs, create a doc following the [Codelab Formatting Guide](FORMAT-GUIDE.md). \nand see the [claat](claat) directory for a detailed description of the `claat` command line tool.\n\nAlso, consider joining the [codelab-authors Google Group](https://groups.google.com/forum/#!forum/codelab-authors),\nwhich connects you with other authors and provides updates on new releases. \n\n## What is this?\n\nFor the past 3+ years, the CLaaT (Codelabs as a Thing) project has given developers around the\nworld a hands-on experience with Google products and tools.  We’ve accumulated over 500 high quality\ncodelabs, served millions of web visitors, and supported over 100 events, from local meetups\nall the way up to Google I/O.\n\nThis project has been implemented as a volunteer project by a small group of dedicated Googlers\nwho care deeply about this kind of “learning by doing” approach to education.\n\n## What's special about this tool?\n\n* Powerful and flexible authoring flow via Google Docs\n* Optional support for authoring in Markdown text\n* Ability to produce interactive web or markdown tutorials without writing any code\n* Easy interactive previewing\n* Usage monitoring via Google Analytics\n* Support for multiple target environments (kiosk, web, markdown, offline, etc.)\n* Support for anonymous use - ideal for public computers at developer events\n* Looks great, with a responsive web implementation\n* Remembers where the student left off when returning to a codelab\n* Mobile friendly user experience\n\n## Can I use this to create my own codelabs and serve my own codelabs online?\n\nYes, the claat tool and the serving mechanism can be used by anyone to author their\nown codelabs and to serve up their own codelabs on the web.\n\nYou can also use this tool to create a nice looking summary page like the one you see on the official [Google Codelabs site](https://g.co/codelabs).\n\nIf you're interested in authoring codelabs, join [codelab-authors group](https://groups.google.com/forum/#!forum/codelab-authors),\nwhich connects you with other authors and provides access to the\n[Codelab Formatting Guide](FORMAT-GUIDE.md).\n\n## Ok, how do I use it?\n\nCheck out this [excellent tutorial](https://medium.com/@zarinlo/publish-technical-tutorials-in-google-codelab-format-b07ef76972cd).\n\n1. Create a doc following the syntax conventions described in the [Codelab Formatting Guide](FORMAT-GUIDE.md). Here’s an [example doc](https://docs.google.com/document/d/1E6XMcdTexh5O8JwGy42SY3Ehzi8gOfUGiqTiUX6N04o/). Feel free to copy that doc as a starter template. Once you have your own source doc, note its DocId, which is the long string near the end of the URL (right after docs.google.com/document/d/).\n\n1. Make one or more changes and preview your codelab, using the preview app provided by Google. To preview a codelab, install the [Preview Codelab Chrome extension](https://chrome.google.com/webstore/detail/preview-codelab/lhojjnijnkiglhkggagbapfonpdlinji) in your browser. Now you can preview a codelab directly from the Google Doc view by clicking the Chrome extension’s button, which will open a new tab to display the preview. Alternatively, navigate manually to https://codelabs-preview.appspot.com/?file_id=\u003cgoogle-doc-id\u003e\n\n1. Install the claat command -- see the [README in the claat directory](https://github.com/googlecodelabs/tools/blob/master/claat/README.md) of this repo for instructions..\n\n1. Run the claat command to transform the doc contents into one of the supported output formats. The default supported formats are html and markdown but the claat tool supports adding additional formats by specifying a path to a Go template. For example, using the example document above:\n\n        $ claat export 1rpHleSSeY-MJZ8JvncvYA8CFqlnlcrW8-a4uEaqizPY  \n        ok      your-first-pwapp\n\n    You can also specify a markdown document (.md file) as input. It has to adhere to the syntax conventions described [here](https://github.com/googlecodelabs/tools/tree/master/claat/parser/md)\n\n        $ claat export document.md\n        ok      your-md-based-codelab\n\n1. Run the claat serve command.\n\n        $ claat serve\n\nThis will start a local web server and open a browser tab to the local server. Click on the\nhyperlink represent your codelab of interest to experience a fully rendered version.\n\n## How do I generate my own landing page?\n\nSee instructions in the [site directory's readme](site/README.md).\n\n## How do I generate a custom view?\n\nCopy the [sample view](site/app/views/vslive), customize it to your liking,\ntag and rebuild the codelabs you want included, and then generate your view.\n\n## How do I publish my codelabs?\n\nThe output generated by `claat` is a purely static set of HTML or Markdown code. As such,\nit can be served by any web serving mechanism, including any of the following options:\n\n* Github Pages (`*.github.io`)\n* [Google App Engine](https://cloud.google.com/appengine)\n* [Firebase Static Serving](https://firebase.google.com/products/hosting)\n* [Google Cloud Storage](https://cloud.google.com/storage)\n* Amazon Web Services S3\n* Netlify\n* Any open source web server (Nginx, Apache)\n* `python -m SimpleHTTPServer` (Python 2)\n* `python3 -m http.server` (Python 3)\n\nSimply commit the artifacts generated by the claat command into your preferred serving vehicle\nand you should be ready to go.\n\nThe [site directory](site) contains tools for building your own custom landing page(s) and publishing both landing\npages and codelabs to Google Cloud Storage.\n\n## Why bother with this approach when I can write tutorials directly in Markdown?\n\nSome people like the Google Docs authoring flow, others prefer to specify their codelabs\ndirectly in Markdown. Using the Docs approach, one source format can be used to generate\nnumerous output formats. Also, you can use a doc for the initial formulation stage, where\nWYSIWYG and easy collaboration are extremely useful. Once the content stabilizes, typically\nafter the first launch, you are free to make the generated markdown your source of truth\nand discard the Google Doc as a controlling source. This is desirable because it gives you\nthe ability to manage the content as code in a source control system, but it comes at the\ncost of having to commit to one specific output format, or having to maintain multiple\nsources of truth.\n\nThis tool and corresponding authoring approach are agnostic with respect to whether (and when)\nyou choose to manage your source as a Google Doc or as Markdown text checked into a repo.\nThe only hard and fast rule is that, at any one point in time, you should choose one or the\nother. Trying to simultaneously maintain a doc and a corresponding repository is a recipe\nfor disaster.\n\n## What are the supported input formats?\n\n* Google Docs (following FORMAT-GUIDE.md formatting conventions)\n* Markdown\n\n## What are the supported output formats?\n\n* Google Codelabs - HTML and Markdown\n* Qwiklabs - Markdown\n* Cloud Shell Tutorials - Markdown with special directives\n* Jupyter, Kaggle Kernels, Colaboratory, et. al. - Markdown with format specific cells\n\nThere’s no one “best” publication format. Each format has its own advantages,\ndisadvantages, community, and application domain. For example, Jupyter has a very strong\nfollowing in the data science and Python communities.\n\nThis variety of formats is healthy because we’re seeing new innovative approaches all the\ntime (for example, see observablehq.com, which recently launched their Beta release).\n\nWhile this evolving format ecosystem is generally a good thing, having to maintain tutorials in\nmultiple formats, or switch from one format to another can be painful. The Codelabs doc format\n(as specified in FORMAT-GUIDE.md) can provide a high level specification for maintaining\na single source of truth, programmatically translated into one or more tutorial specific formats.\n\n## Can I contribute?\n\nYes, by all means. Have feature ideas? Send us a pull request or file a bug.\n\n## Where did this come from?\n\nFor several years, Googlers would rush to build new tutorials and related assets for our\nannual developer event, Google I/O. But every year the authoring platform and distribution\nmechanism changed. As a result, there was little reuse of content and serving infrastructure,\nAnd every year we essentially kept reinventing the same wheel.\n\nFor Google I/O 2014, Shawn Simister wrote a Python program which retrieved\nspecially formatted documents from Google Drive, parsed them, and generated\na nice interactive web-based user experience. This allowed authors to design their\ncodelabs using Google Docs, with its great interactivity and collaboration features,\nand automatically convert those documents into beautiful web based tutorials,\nwithout needing to write a single line of code.\n\nLater, Ewa Gasperowicz wrote a site generator, supporting the ability to\npublish custom landing pages, with associated branding and an inventory of codelabs\nspecially curated for a given event.\n\nAlex Vaghin later rewrote Shawn's Python program as a statically linked Go program (the claat command in this repo), eliminating many runtime dependencies, improving translation\nperformance. Alex also added, among many other enhancements, a proper abstract syntax\ntree (to facilitate translation to different output formats), an app engine based previewer, an extensible rendering engine, support for generating markdown output. Alex also wrote the web serving infrastructure, the build tooling (based on gulp), and, with the author, the ability to self-publish codelabs directly from the preview app.\n\nClare Bayley has been the guru of onsite codelab experiences, running events large and small, while Sam Thorogood and Chris Broadfoot made major contributions to the onsite kiosks you may have seen at Google I/O.\n\nEric Bidelman redesigned the codelab user interface using Polymer components and built the g.co/codelabs landing page, to provide a beautiful user experience that looks great and works equally well on desktop and mobile devices.\n\nLots of other contributions have been made over the years and I’m sure that I’m neglecting some important advances but for the sake of brevity, I’ll leave it at that.\n\n## Acknowledgements\n\nGoogle Codelabs exists thanks to the talents and efforts of many fine volunteers, including:\nAlex Vaghin, Marc Cohen, Shawn Simister, Ewa Gasperowicz, Eric Bidelman, Robert Kubis, Clare Bayley, Cassie Recher, Chris Broadfoot, Sam Thorogood, Ryan Seys, and the many codelab authors, inside and outside of Google, who have generated a veritable [treasure trove of content](https://g.co/codelabs).\n\n## Notes\n\nThis is not an official Google product.\n","funding_links":[],"categories":["Go","HTML (17)","Workshop training","etc"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgooglecodelabs%2Ftools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgooglecodelabs%2Ftools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgooglecodelabs%2Ftools/lists"}