{"id":47865298,"url":"https://github.com/kleinpanic/cs3704-canvas-project","last_synced_at":"2026-06-10T09:00:31.959Z","repository":{"id":349039398,"uuid":"1200823574","full_name":"kleinpanic/CS3704-Canvas-Project","owner":"kleinpanic","description":"CS3704 Canvas Project - team-maintained Canvas TUI and shared-core architecture repo","archived":false,"fork":false,"pushed_at":"2026-05-31T07:33:07.000Z","size":4674,"stargazers_count":1,"open_issues_count":10,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-31T09:22:17.257Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://kleinpanic.github.io/CS3704-Canvas-Project/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kleinpanic.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":"MAINTAINERS.md","copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-03T21:42:59.000Z","updated_at":"2026-05-23T00:32:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kleinpanic/CS3704-Canvas-Project","commit_stats":null,"previous_names":["kleinpanic/cs7304-canvas-project"],"tags_count":49,"template":false,"template_full_name":null,"purl":"pkg:github/kleinpanic/CS3704-Canvas-Project","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kleinpanic%2FCS3704-Canvas-Project","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kleinpanic%2FCS3704-Canvas-Project/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kleinpanic%2FCS3704-Canvas-Project/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kleinpanic%2FCS3704-Canvas-Project/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kleinpanic","download_url":"https://codeload.github.com/kleinpanic/CS3704-Canvas-Project/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kleinpanic%2FCS3704-Canvas-Project/sbom","scorecard":{"id":1247212,"data":{"date":"2026-05-07T20:02:21Z","repo":{"name":"github.com/kleinpanic/CS3704-Canvas-Project","commit":"5c98ea788992ed294d6a49681ed24051f63b1aa6"},"scorecard":{"version":"v5.1.1","commit":"cd152cb6742c5b8f2f3d2b5193b41d9c50905198"},"score":6.2,"checks":[{"name":"Maintained","score":0,"reason":"project was created in last 90 days. please review its contents carefully","details":["Warn: Repository was created in last 90 days."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#maintained"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#security-policy"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#dependency-update-tool"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#code-review"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#dangerous-workflow"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":9,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: jobLevel 'contents' permission set to 'write': .github/workflows/all-contributors.yml:13","Warn: jobLevel 'actions' permission set to 'write': .github/workflows/cleanup.yml:16","Info: jobLevel 'contents' permission set to 'read': .github/workflows/docker.yml:19","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/nightly.yml:15","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release-drafter.yml:13","Info: jobLevel 'actions' permission set to 'read': .github/workflows/release.yml:496","Warn: jobLevel 'security-events' permission set to 'write': .github/workflows/scorecard-gate.yml:20","Info: jobLevel 'contents' permission set to 'read': .github/workflows/scorecard-gate.yml:22","Info: jobLevel 'actions' permission set to 'read': .github/workflows/scorecard-gate.yml:23","Info: jobLevel 'contents' permission set to 'read': .github/workflows/scorecard.yml:18","Info: jobLevel 'actions' permission set to 'read': .github/workflows/scorecard.yml:19","Info: jobLevel 'contents' permission set to 'read': .github/workflows/security.yml:47","Info: jobLevel 'pull-requests' permission set to 'read': .github/workflows/security.yml:48","Info: jobLevel 'contents' permission set to 'read': .github/workflows/security.yml:21","Info: jobLevel 'actions' permission set to 'read': .github/workflows/security.yml:20","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/wiki-sync.yml:16","Info: topLevel permissions set to 'read-all': .github/workflows/all-contributors.yml:7","Info: topLevel 'contents' permission set to 'read': .github/workflows/branch-policy.yml:8","Info: topLevel 'contents' permission set to 'read': .github/workflows/ci.yml:10","Info: topLevel permissions set to 'read-all': .github/workflows/cleanup.yml:10","Info: topLevel permissions set to 'read-all': .github/workflows/coverage.yml:9","Info: topLevel 'contents' permission set to 'read': .github/workflows/dataset-validation.yml:10","Info: topLevel 'contents' permission set to 'read': .github/workflows/deploy-hf-space.yml:13","Info: topLevel 'contents' permission set to 'read': .github/workflows/deploy-pii-space.yml:11","Info: topLevel permissions set to 'read-all': .github/workflows/docker.yml:12","Info: topLevel 'contents' permission set to 'read': .github/workflows/labeler.yml:8","Info: topLevel permissions set to 'read-all': .github/workflows/nightly.yml:6","Info: topLevel 'contents' permission set to 'read': .github/workflows/pages.yml:9","Info: topLevel 'pull-requests' permission set to 'read': .github/workflows/pr-quality.yml:7","Info: topLevel 'contents' permission set to 'read': .github/workflows/pr-quality.yml:8","Info: topLevel 'contents' permission set to 'read': .github/workflows/quick-checks.yml:12","Info: topLevel permissions set to 'read-all': .github/workflows/release-drafter.yml:7","Info: topLevel permissions set to 'read-all': .github/workflows/release.yml:8","Info: topLevel permissions set to 'read-all': .github/workflows/repo-org.yml:14","Info: topLevel permissions set to 'read-all': .github/workflows/scorecard-gate.yml:13","Info: topLevel permissions set to 'read-all': .github/workflows/scorecard.yml:9","Info: topLevel 'contents' permission set to 'read': .github/workflows/security.yml:12","Warn: topLevel 'security-events' permission set to 'write': .github/workflows/security.yml:13","Info: topLevel 'contents' permission set to 'read': .github/workflows/version-check.yml:6","Info: topLevel permissions set to 'read-all': .github/workflows/wiki-sync.yml:10"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":6,"reason":"dependency not pinned by hash detected -- score normalized to 6","details":["Info: Possibly incomplete results: error parsing shell code: \"foo(\" must be followed by ): huggingface/pii-scrub/Dockerfile:12-18","Warn: pipCommand not pinned by hash: docker/canvas-tui/Dockerfile:14","Warn: pipCommand not pinned by hash: huggingface/pii-scrub/Dockerfile:7-8","Warn: pipCommand not pinned by hash: examples/contribute-data.sh:30","Warn: downloadThenRun not pinned by hash: proxy/deploy-curl.sh:40","Warn: downloadThenRun not pinned by hash: proxy/deploy-curl.sh:47","Warn: downloadThenRun not pinned by hash: proxy/deploy-curl.sh:54","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:39","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:65","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:66","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:126","Warn: pipCommand not pinned by hash: .github/workflows/coverage.yml:29","Warn: pipCommand not pinned by hash: .github/workflows/coverage.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/coverage.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/coverage.yml:32","Warn: pipCommand not pinned by hash: .github/workflows/dataset-validation.yml:36","Warn: pipCommand not pinned by hash: .github/workflows/deploy-hf-space.yml:97","Warn: pipCommand not pinned by hash: .github/workflows/deploy-hf-space.yml:33","Warn: pipCommand not pinned by hash: .github/workflows/deploy-pii-space.yml:27","Warn: pipCommand not pinned by hash: .github/workflows/nightly.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/pages.yml:39","Warn: pipCommand not pinned by hash: .github/workflows/quick-checks.yml:41","Warn: pipCommand not pinned by hash: .github/workflows/quick-checks.yml:63","Warn: pipCommand not pinned by hash: .github/workflows/quick-checks.yml:87","Warn: pipCommand not pinned by hash: .github/workflows/release.yml:149","Warn: pipCommand not pinned by hash: .github/workflows/release.yml:369","Warn: pipCommand not pinned by hash: .github/workflows/release.yml:413","Warn: pipCommand not pinned by hash: .github/workflows/release.yml:206","Warn: npmCommand not pinned by hash: .github/workflows/release.yml:275","Info:  64 out of  64 GitHub-owned GitHubAction dependencies pinned","Info:  62 out of  62 third-party GitHubAction dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned","Info:   2 out of   2 containerImage dependencies pinned","Info:   0 out of  24 pipCommand dependencies pinned","Info:   0 out of   3 downloadThenRun 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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#pinned-dependencies"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":0,"reason":"20 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-39mp-8hj3-5c49","Warn: Project is vulnerable to: GHSA-5cpq-9538-jm2j","Warn: Project is vulnerable to: GHSA-8jw3-6x8j-v96g","Warn: Project is vulnerable to: GHSA-h3h8-3v2v-rg7m","Warn: Project is vulnerable to: GHSA-j2jg-fq62-7c3h","Warn: Project is vulnerable to: GHSA-jmh7-g254-2cq9","Warn: Project is vulnerable to: GHSA-pfjf-5gxr-995x","Warn: Project is vulnerable to: GHSA-wmjh-cpqj-4v6x","Warn: Project is vulnerable to: GHSA-69w3-r845-3855","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: GHSA-gc5v-m9x4-r6x2","Warn: Project is vulnerable to: PYSEC-2023-74 / GHSA-j8r2-6x86-q33q","Warn: Project is vulnerable to: GHSA-2xpw-w6gg-jr37","Warn: Project is vulnerable to: GHSA-34jh-p97f-mpxf","Warn: Project is vulnerable to: GHSA-38jv-5279-wg99","Warn: Project is vulnerable to: PYSEC-2023-212 / GHSA-g4mx-q9vg-27p4","Warn: Project is vulnerable to: GHSA-gm62-xv2j-4w53","Warn: Project is vulnerable to: GHSA-pq67-6m6q-mj2v","Warn: Project is vulnerable to: PYSEC-2023-192 / GHSA-v845-jxx5-vc9f"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: SAST configuration detected: CodeQL","Info: all commits (30) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#sast"}},{"name":"Branch-Protection","score":4,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Info: 'branch protection settings apply to administrators' is required to merge on branch 'main'","Info: 'stale review dismissal' is required to merge on branch 'main'","Warn: branch 'main' does not require approvers","Info: codeowner review is required on branch 'main'","Warn: 'last push approval' is disabled on branch 'main'","Info: 'up-to-date branches' is required to merge on branch 'main'","Info: status check found to merge onto on branch 'main'","Info: PRs are required in order to make changes on branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":10,"reason":"5 out of the last 5 releases have a total of 5 signed artifacts.","details":["Info: provenance for release artifact: multiple.intoto.jsonl: https://github.com/kleinpanic/CS3704-Canvas-Project/releases/tag/v2.0.9","Info: provenance for release artifact: multiple.intoto.jsonl: https://github.com/kleinpanic/CS3704-Canvas-Project/releases/tag/v2.0.8","Info: provenance for release artifact: multiple.intoto.jsonl: https://github.com/kleinpanic/CS3704-Canvas-Project/releases/tag/v2.0.7","Info: provenance for release artifact: multiple.intoto.jsonl: https://github.com/kleinpanic/CS3704-Canvas-Project/releases/tag/v2.0.6","Info: provenance for release artifact: multiple.intoto.jsonl: https://github.com/kleinpanic/CS3704-Canvas-Project/releases/tag/v2.0.5"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#license"}},{"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#fuzzing"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/docker.yml:15"],"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/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#packaging"}},{"name":"Contributors","score":0,"reason":"project has 0 contributing companies or organizations -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#contributors"}},{"name":"CI-Tests","score":10,"reason":"30 out of 30 merged PRs checked by a CI test -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/cd152cb6742c5b8f2f3d2b5193b41d9c50905198/docs/checks.md#ci-tests"}}]},"last_synced_at":"2026-05-10T08:42:08.428Z","repository_id":349039398,"created_at":"2026-05-10T08:42:08.428Z","updated_at":"2026-05-10T08:42:08.428Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34144680,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":"2026-04-04T00:08:38.159Z","updated_at":"2026-06-10T09:00:31.845Z","avatar_url":"https://github.com/kleinpanic.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CS3704 Canvas Project\n\nA maintainable, team-ready **Canvas LMS productivity client** with a Textual TUI frontend, Chrome extension, Python SDK, and a fine-tuned calendar agent — with a documented shared-core architecture.\n\n---\n\n\u003c!-- hero: Phase 10 --\u003e\n\u003e **Canvas Tracker** — the fastest path from Canvas API token to a local calendar agent,\n\u003e polished TUI, and contribution-ready dataset pipeline.\n\n\u003c!-- asciinema cast: docs-site/casts/tui-demo.cast --\u003e\n\u003c!-- TODO: record cast with `asciinema rec docs-site/casts/tui-demo.cast` + upload to asciinema.org --\u003e\n\u003c!-- Static screenshot fallback: --\u003e\n![TUI demo](docs-site/screenshots/10-final-home.png)\n\n| Deploy | Link |\n|--------|------|\n| PyPI (SDK) | [![PyPI canvas-sdk](https://img.shields.io/pypi/v/canvas-sdk?label=canvas-sdk)](https://pypi.org/project/canvas-sdk/) |\n| Codespaces | [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/kleinpanic/CS3704-Canvas-Project) |\n| HF Space | [![Open in HF Spaces](https://huggingface.co/datasets/huggingface/badges/resolve/main/open-in-hf-spaces-sm.svg)](https://huggingface.co/spaces/kleinpanic93/canvas-calendar-agent-demo) |\n| Docker | [![ghcr.io](https://img.shields.io/badge/ghcr.io-canvas--tui-2496ED?logo=docker\u0026logoColor=white)](https://github.com/kleinpanic/CS3704-Canvas-Project/pkgs/container/canvas-tui) |\n\nSee [Quick Start](docs/QUICKSTART.md) · [Examples](examples/) · [Public Roadmap](ROADMAP.md)\n\n---\n\n\u003c!-- badges: CI/CD | Distribution | Repo health | Tooling | HF/ML | Dev buttons (Phase 9) --\u003e\n[![CI](https://img.shields.io/github/actions/workflow/status/kleinpanic/CS3704-Canvas-Project/ci.yml?branch=main\u0026label=CI)](https://github.com/kleinpanic/CS3704-Canvas-Project/actions/workflows/ci.yml)\n[![Security](https://img.shields.io/github/actions/workflow/status/kleinpanic/CS3704-Canvas-Project/security.yml?branch=main\u0026label=Security)](https://github.com/kleinpanic/CS3704-Canvas-Project/actions/workflows/security.yml)\n[![Pages](https://img.shields.io/github/actions/workflow/status/kleinpanic/CS3704-Canvas-Project/pages.yml?branch=main\u0026label=Pages)](https://github.com/kleinpanic/CS3704-Canvas-Project/actions/workflows/pages.yml)\n[![Release](https://img.shields.io/github/actions/workflow/status/kleinpanic/CS3704-Canvas-Project/release.yml?label=Release)](https://github.com/kleinpanic/CS3704-Canvas-Project/actions/workflows/release.yml)\n\n\u003c!-- codecov badge: removed pending codecov.io registration; see Phase 5/8 for restoration when CODECOV_TOKEN is wired --\u003e\n\n[![PyPI canvas-sdk](https://img.shields.io/pypi/v/canvas-sdk?label=canvas-sdk)](https://pypi.org/project/canvas-sdk/)\n\n\u003c!-- canvas-tui badge restored when #177 ships --\u003e\n\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/canvas-sdk)](https://pypi.org/project/canvas-sdk/)\n[![ghcr.io](https://img.shields.io/badge/ghcr.io-canvas--tui-2496ED?logo=docker\u0026logoColor=white)](https://github.com/kleinpanic/CS3704-Canvas-Project/pkgs/container/canvas-tui)\n\u003cbr\u003e\n[![release](https://img.shields.io/github/v/release/kleinpanic/CS3704-Canvas-Project?label=release)](https://github.com/kleinpanic/CS3704-Canvas-Project/releases)\n[![last commit](https://img.shields.io/github/last-commit/kleinpanic/CS3704-Canvas-Project)](https://github.com/kleinpanic/CS3704-Canvas-Project/commits/main)\n[![activity](https://img.shields.io/github/commit-activity/m/kleinpanic/CS3704-Canvas-Project?label=activity)](https://github.com/kleinpanic/CS3704-Canvas-Project/commits/main)\n[![contributors](https://img.shields.io/github/contributors/kleinpanic/CS3704-Canvas-Project)](https://github.com/kleinpanic/CS3704-Canvas-Project/graphs/contributors)\n\u003cbr\u003e\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE)\n[![code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000?logo=ruff)](https://github.com/astral-sh/ruff)\n[![mypy: advisory](https://img.shields.io/badge/mypy-advisory-yellow?logo=python\u0026logoColor=white)](https://github.com/kleinpanic/CS3704-Canvas-Project/actions/workflows/quick-checks.yml)\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white)](https://pre-commit.com/)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n[![OSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/kleinpanic/CS3704-Canvas-Project/badge)](https://securityscorecards.dev/viewer/?uri=github.com/kleinpanic/CS3704-Canvas-Project)\n\u003cbr\u003e\n[![Open in HF Spaces](https://huggingface.co/datasets/huggingface/badges/resolve/main/open-in-hf-spaces-sm.svg)](https://huggingface.co/spaces/kleinpanic93/canvas-calendar-agent-demo)\n[![Open in HF Spaces](https://huggingface.co/datasets/huggingface/badges/resolve/main/open-in-hf-spaces-sm.svg)](https://huggingface.co/spaces/kleinpanic93/canvas-pii-scrub)\n[![HF Model](https://img.shields.io/badge/🤗_Model-canvas--calendar--agent--v7--dpo-yellow)](https://huggingface.co/kleinpanic93/canvas-calendar-agent-v7-dpo)\n[![HF Dataset](https://img.shields.io/badge/🤗_Dataset-canvas--calendar--preferences--v7-blue)](https://huggingface.co/datasets/kleinpanic93/canvas-calendar-preferences-v7)\n[![HF Collection](https://img.shields.io/badge/🤗_Collection-Canvas_Calendar_Agent_v3.0-yellow)](https://huggingface.co/collections/kleinpanic93/canvas-calendar-agent-v30-69fa6462f697e0342b21dfe0)\n\u003cbr\u003e\n[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/kleinpanic/CS3704-Canvas-Project)\n[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers\u0026message=Open\u0026color=blue\u0026logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/kleinpanic/CS3704-Canvas-Project)\n\n---\n\n## Distribution\n\n| Surface | Channel | Status |\n|---------|---------|--------|\n| **canvas-sdk** (Python) | [PyPI](https://pypi.org/project/canvas-sdk/) | live — v1.2.3 on PyPI |\n| **canvas-tui** (Python) | [PyPI](https://pypi.org/project/canvas-tui/) | not yet published — pyproject.toml v2.0.0; tracked in [#177](https://github.com/kleinpanic/CS3704-Canvas-Project/issues/177) |\n| **canvas-tui** (Docker) | `ghcr.io/kleinpanic/canvas-tui` | live — built nightly + on tag (#140) |\n| **Chrome extension** | [Chrome Web Store](https://chromewebstore.google.com/) | listing in progress — install via `Load unpacked` for now |\n| **HF Space demo** | [Live](https://huggingface.co/spaces/kleinpanic93/canvas-calendar-agent-demo) | live — auto-deploys on push to `main` |\n| **HF Model** | [v7-DPO](https://huggingface.co/kleinpanic93/canvas-calendar-agent-v7-dpo) | live |\n\n\u003e **canvas-sdk v1.2.3 live on PyPI (API token).** OIDC trusted publisher not yet registered at pypi.org. Chrome Web Store listing in progress — install via `Load unpacked` for now.\n\n---\n\n## Quick Start\n\n### Chrome Extension\n\n1. Clone or download this repo.\n2. In Chrome, open `chrome://extensions/` and enable **Developer mode**.\n3. Click **Load unpacked** and select the `extension/` directory.\n4. Pin the extension, open a Canvas page, and click the icon.\n\n### Python SDK\n\n```bash\npip install canvas-sdk[autodownload]    # fetches the v7-dpo Gemma4 model from HF on first run\npip install canvas-sdk[gemini]          # optional Gemini fallback\npip install canvas-sdk[all]             # both\n```\n\n\u003e **Note:** PyPI publishes v1.2.3. The v2.0.0 local source (with the updated agent architecture)\n\u003e can be installed with `pip install -e src/sdk/`.\n\n```python\nimport os\nfrom canvas_sdk import CanvasAgent\n\nos.environ[\"CANVAS_TOKEN\"]    = \"...\"        # your Canvas API token\nos.environ[\"CANVAS_BASE_URL\"] = \"https://canvas.vt.edu\"\n\nagent = CanvasAgent.auto()                   # auto-resolves: env -\u003e local -\u003e HF -\u003e Gemini\nprint(agent.run(\"What is due this week?\"))\n```\n\n`CanvasAgent.auto()` resolution order:\n1. `CANVAS_LLM_ENDPOINT` env (skip auto-download, use your own server)\n2. Local cache at `~/.cache/canvas-agent/v7-dpo/` (spawns vLLM on `:8765`)\n3. Download `kleinpanic93/canvas-calendar-agent-v7-dpo` from HF, then (2)\n4. Fall back to Gemini (`gemini-2.5-flash` by default)\n\n### TUI (Terminal UI)\n\n```bash\nexport CANVAS_TOKEN=\"your_canvas_token_here\"\nexport CANVAS_BASE_URL=\"https://canvas.yourschool.edu\"  # required — no default; tool exits with error if unset\n\npipx install .          # recommended\n# or: pip install .\n\ncanvas-tui\n```\n\n---\n\n## Live Demo\n\nTry the fine-tuned Canvas Calendar Agent in your browser — no install required, no tokens needed:\n\n- **Agent demo** (mock Canvas data, hosted DPO model): https://kleinpanic.github.io/CS3704-Canvas-Project/agent-demo/\n- **HF Space** (full model, mock tools): https://huggingface.co/spaces/kleinpanic93/canvas-calendar-agent-demo\n- **HF Collection** (v3.0 method matrix): https://huggingface.co/collections/kleinpanic93/canvas-calendar-agent-v30-69fa6462f697e0342b21dfe0\n\n### Demo architecture (no tokens in client JS)\n\n```\nBrowser  -\u003e  Cloudflare Worker  -\u003e  HF Space (ZeroGPU)\n              ^                       ^\n              |                       |\n              | HF_TOKEN held as      | Gemma4 v7-dpo behind\n              | Cloudflare secret     | gradio 5 ChatInterface +\n              | (never reaches the    | 18 mock tool dispatchers\n              | browser)              |\n```\n\nThe HF token is stored as a Cloudflare Worker secret. Public clients only\nsee the proxy URL (`cs3704-demo-proxy.kleinpanic.workers.dev`); they never\nreceive any credential. See [`proxy/README.md`](proxy/README.md) for the\ndeploy procedure and [`proxy/iframe-fallback.html`](proxy/iframe-fallback.html)\nfor a zero-infra alternative that embeds the Space directly.\n\n\u003e **Token policy:** the SDK reads `CANVAS_TOKEN` and `GOOGLE_API_KEY` from\n\u003e your local environment. Tokens never enter the published browser demo,\n\u003e the GH Pages site, or any committed file. The Cloudflare Worker proxy is\n\u003e the only place an HF token is held, and it sits server-side as a Cloudflare\n\u003e secret. If you fork this project and host your own demo, follow the same\n\u003e pattern — see [`proxy/README.md`](proxy/README.md).\n\n---\n\n## Documentation\n\n- **[Docs site](https://kleinpanic.github.io/CS3704-Canvas-Project/)** — live project docs\n- **[Agent demo](https://kleinpanic.github.io/CS3704-Canvas-Project/agent-demo/)** — chat with the Canvas Calendar Agent in your browser\n- **[Roadmap](https://kleinpanic.github.io/CS3704-Canvas-Project/roadmap.html)** — planned milestones and feature backlog\n- **[HF Space](https://huggingface.co/spaces/kleinpanic93/canvas-calendar-agent-demo)** — full v7-dpo model behind a Gradio chat UI\n- **[How it Works](https://kleinpanic.github.io/CS3704-Canvas-Project/agent-demo/method.html)** — DPO methodology, 9-method ablation matrix, G1–G13 guardrails, bench harness\n- **[PyPI: canvas-sdk](https://pypi.org/project/canvas-sdk/)** — `pip install canvas-sdk`\n- **[Architecture docs](https://kleinpanic.github.io/CS3704-Canvas-Project/docs/architecture/)** — system design decisions\n- **[Browser extension docs](https://kleinpanic.github.io/CS3704-Canvas-Project/docs/extension/)** — shared client/runtime architecture\n- **[Contributing](CONTRIBUTING.md)** — contribution guidelines and developer setup\n- **[Maintainers](MAINTAINERS.md)** — maintainer responsibilities\n- **[Security policy](SECURITY.md)** — security procedures\n\n---\n\n## Development\n\nFor team workflow, branch naming, repo structure, and dev setup, see [`CONTRIBUTING.md`](CONTRIBUTING.md).\n\n---\n\n## Contributors\n\n[![Contributors](https://contrib.rocks/image?repo=kleinpanic/CS3704-Canvas-Project)](https://github.com/kleinpanic/CS3704-Canvas-Project/graphs/contributors)\n\nMade with [contrib.rocks](https://contrib.rocks).\n\n---\n\n## License\n\nGPL-3.0-or-later. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkleinpanic%2Fcs3704-canvas-project","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkleinpanic%2Fcs3704-canvas-project","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkleinpanic%2Fcs3704-canvas-project/lists"}