01
Orientation
BetterHackdays is an open-source Hack Day room: it connects coding agents, matches people into teams, and turns pasted event text into a shared kickoff plan. The RFP Connector is the part of BetterHackdays that opens KnowB's project requests for proposals to outside builders.
Run the connector as an MCP server inside the agent you already use, or call the same functions over REST. Either way you can:
- browse the approved public RFPs and the live public projects behind them;
- check a new idea against the canonical idea catalogue, the open projects, and the knowb.run showcase;
- send a refinement, an expression of interest, or an access request to a maintainer, with your identity verified by GitHub.
The connector is the source
This site explains and points. Every RFP read, comparison, and request happens in the connector, so answers are always current.
The catalogue stays canonical
Idea suggestions live in Cloud Builder Stack. The connector reads them live and never copies them here.
Requests stay private
Request details go to maintainers, not to a public issue, a feed, or this page.
02
Quickstart
You need Python 3.12, Git, and an MCP-capable agent such as Claude Code. Reading RFPs needs no account. Submitting a request needs a GitHub token for your own account, because the token is how the connector knows who you are.
Clone and install
git clone https://github.com/knowb-ai/BetterHackdays.git cd BetterHackdays python3 -m venv .venv .venv/bin/pip install -r requirements.txtConnect your agent
Pick your client. Run the command from the repository root so the paths resolve.
claude mcp add betterhackdays \ -e PYTHONPATH="$PWD" \ -e DATABASE_URL="sqlite:///$PWD/betterhackdays.db" \ -- "$PWD/.venv/bin/python" -m app.mcp_server claude mcp list # betterhackdays: ... ✔ Connected{ "mcpServers": { "betterhackdays": { "command": "/path/to/BetterHackdays/.venv/bin/python", "args": ["-m", "app.mcp_server"], "env": { "PYTHONPATH": "/path/to/BetterHackdays", "DATABASE_URL": "sqlite:////path/to/BetterHackdays/betterhackdays.db" } } } }.venv/bin/uvicorn app.main:app --reload --port 8000 # in another terminal curl -s "http://localhost:8000/rfps/search?q=inbox"Interactive API docs:
http://localhost:8000/docs.Ask in plain language
Your agent picks the right tool. Try:
- “List the KnowB RFPs and group them by theme.”
- “Compare MarkSweep and Subtracktor for a two-person weekend team.”
- “Would a calendar-aware inbox triage idea qualify for the catalogue?”
- “Draft an expression of interest for Underminer and show me the preview.”
Add your identity, only to send requests
Give the server a fine-grained GitHub token for your own account in
GITHUB_TOKEN. Keep it in your client's local config or a secret manager, never in a repository or a chat message. The connector resolves your login from the token with GitHub; it never accepts a login you type.
03
Explore RFPs
The connector serves two kinds of entry. Website RFPs are the open briefs listed on knowb.run. Live projects are public repositories already in motion that welcome help. Idea suggestions are kept separate, so a brainstorm is never mistaken for a commitment.
- 01ShadowCaster
shadowcasterWebsite RFPInvestigate how LinkedIn and Instagram content policies affect reach, moderation, and event visibility for artists, creators, and community workers, especially in marginalized communities.
- 02Underminer
underminerWebsite RFPExtract semantic understanding from paywalled reporting and reconstruct the story from alternate sources plus LLM context-tracing experiments.
- 03X-Poser
x-poserWebsite RFPSubmit an X link, run claim checks, and generate a report that marks the post as true, uncertain, or fabricated, with export-ready output for sharing on X.
- 04Precongnition
precongnitionWebsite RFPDetect missing or mismatched conference talks, tutorials, or demos, then crawl for alternate watch links and nearest neighboring sessions.
- 05MarkSweep
marksweepWebsite RFPA browser extension granted control over your active tab that walks every unread message in your open inbox, checks each against relevance rules you control, marks non-matches as read in bulk, and flags matches to stay pinned at the top.
- 06Subtracktor
subtracktorWebsite RFPSubtracktor is a browser extension that connects consent-fully to your email inbox once it detects an inbox open in the active tab. It scans only for account-creation and subscription-confirmation messages, then builds a per-account record of every subscription it finds.
- 07BetterHackdays
betterhackdaysLive projectHelp hack-day organizers move builders from event rules and tracks to a team, a focused idea, and a shared first-hour plan. BetterHackdays brings event context, opt-in participant profiles, matchmaking, and team workspaces into one live flow.
- 08BetterLover
betterloverLive projectTurn a person's chosen cycle, mood, energy, and care preferences into thoughtful, practical suggestions for a partner. The current prototype uses synthetic cycle data and produces a structured plan that can be reviewed before action.
- 09Sepnu Pues
sepnu-puesLive projectHelp people follow through on the tasks they set for themselves through a lightweight daily loop. The prototype pairs a task list with optional safe-cartoon generation, an accountability-email queue, and a prefilled social-post draft.
Generated from the connector's approved public entries when this site was built. Ask the connector for full briefs, scope, outcomes, and safety boundaries.
The four exploration tools
list_project_rfpsEverything approved, with resources listed apart from RFPs. Filter with visibility.
search_project_rfpsFull-text search. Pass include_design_resources to also search the public design system.
read_project_rfpOne brief by ID or title: summary, outcome, scope, and safety boundary.
compare_project_rfpsTwo or more briefs side by side, to help a team choose.
Building something that should look like it belongs to KnowB? The design tools read an allowlist of public files from the knowb.run repository: the design system, brand guidelines, the Org Book, stylesheets, and the pixel icon dictionary.
Edit this section04
Refine ideas
The idea catalogue lives in Cloud Builder Stack, and it stays there. The connector fetches it live each time and fails closed: if the catalogue cannot be read, you get an honest source_unavailable, never a stale copy.
- Fetch
fetch_idea_catalogueRead suggestions live, filtered by query or section.
- Qualify
qualify_ideaA deterministic check against the catalogue, open public projects, and the knowb.run showcase. Duplicates and showcased work come back
not_eligible. - Propose
propose_idea_catalogue_additionPreviews by default. With
submit, it opens a pull request to Cloud Builder Stack, only after a human-reviewed rationale, a named reviewer, and that repository's review rules all check out.
A proposal is a pull request, never a direct write. Cloud Builder Stack's maintainers merge or decline it.
Edit this section05
Contributor requests
A request is not a grant.
Submitting a request never changes who can push to a repository. Access to any repository requires the owner's explicit approval, given by a person, outside the connector. No QR code, slug, match, or submitted form grants access on its own.
Request types
| Request type | Use it to | Requester needs on BetterHackdays |
|---|---|---|
RFP Refinement Draftrefinement_draft | Suggest sharper scope, outcomes, or safety notes for an existing RFP brief. | Read or higher |
Expression of Interestexpression_of_interest | Tell the maintainers you want to work on an RFP, with no access asked for. | Read or higher |
Project Contribution Access Requestcontribution_access_request | Ask to be considered for contributor access to the project behind an RFP. | Read or higher |
Work Elevation Requestwork_elevation_request | Ask for elevated work on a project you already contribute to. | Write, maintain, or admin |
How a request travels
- 1Preview. Call
preview_contributor_requestwith a type, an RFP ID, the scope you want, and a short message. Nothing is sent. Read the draft, and fix it if it is wrong. - 2Submit. Call
submit_contributor_request. The connector verifies your GitHub identity from your token and checks your permission on BetterHackdays. If either check fails you getunauthorized, and nothing leaves your machine. - 3Route. The request is recorded privately and sent to the maintainers at ping@knowb.run. If mail is not configured, you get the complete addressed draft back, plainly marked not sent, to send yourself.
- 4Review. A repository owner reads it and decides. If they approve access, they send the GitHub invitation themselves. Track your own requests with
list_contributor_requests.
Write requests the way you would write to a person: what you want to work on, why, and what you have built before. Leave out passwords, tokens, and private data.
Edit this section06
Permission boundaries
The connector is built to be safe to hand to an agent. These rules are enforced in code and covered by the test suite.
- Identity comes from GitHub, not from you
- Request bodies and tool arguments never carry identity or role claims. The connector resolves your login from your token with the GitHub API and ignores any login or role that is typed in.
- Exact permission, exact repository
- Every write checks your live permission on the one repository it targets. Requests need read or higher on BetterHackdays; work elevation needs write or higher.
- The bot's scope is checked too
- Writes made through the KnowB GitHub App must fit the scopes that app was installed with, and only on an allowlist of public KnowB repositories.
- Access grants are owner-only, and preview-only here
grant_repository_accessonly ever returns a dry run over MCP. Real invitations are sent by the repository owner, by hand.- Failures close, never open
- If GitHub, the catalogue, or an installation lookup cannot be reached, the answer is a refusal or
source_unavailable, never a guess. - Only public material leaves the connector
- RFP briefs are curated summaries. Design resources come from an explicit allowlist of public files. Entries that are not approved for the public never appear on this site.
07
Reference
Both references below are rendered from data/reference.json, which scripts/build_site.py generates from the running code. A test fails if it falls out of date.
MCP tools
29 tools registered by betterhackdays-hack-day.
Explore RFPs
#list_project_rfps
List approved KnowB project RFPs and public resources separately from idea suggestions.
list_project_rfps(visibility: Optional[str] = None)#search_project_rfps
Search approved KnowB project RFPs and optionally allowlisted public design resources.
search_project_rfps(query: str, include_design_resources: bool = False)#read_project_rfp
Read a single approved KnowB project RFP brief by ID or title.
read_project_rfp(rfp_id: str)#compare_project_rfps
Compare two or more approved KnowB project RFPs side-by-side.
compare_project_rfps(rfp_ids: list[str])Public design resources
#list_design_resources
List explicitly allowlisted public design philosophy documents and assets from knowb-ai.github.io.
list_design_resources()#search_design_resources
Search allowlisted public design philosophy documents and assets.
search_design_resources(query: str)#read_design_resource
Read an allowlisted public design philosophy document or asset from knowb-ai.github.io.
read_design_resource(path: str, repo: str = 'knowb-ai/knowb-ai.github.io')Refine ideas
#fetch_idea_catalogue
Fetch the canonical Cloud Builder Stack idea catalogue live and return ideation-only suggestions.
fetch_idea_catalogue(query: Optional[str] = None, section: Optional[str] = None, limit: Optional[int] = None)#qualify_idea
Deterministically qualify a candidate idea against the canonical catalogue, open public projects, and showcase.
qualify_idea(title: str, summary: str, alignment_evidence: Optional[str] = None, human_reviewed_rationale: Optional[str] = None, reviewed_by: Optional[str] = None)#propose_idea_catalogue_addition Writes with review
Preview and optionally submit a qualified, human-reviewed idea as a PR to Cloud Builder Stack.
propose_idea_catalogue_addition(title: str, summary: str, alignment_evidence: Optional[str] = None, human_reviewed_rationale: Optional[str] = None, reviewed_by: Optional[str] = None, section: str = '10. Stronger Actual AI System Ideas', submit: bool = False)Contributor requests
#preview_contributor_request
Preview a refinement draft, expression of interest, contribution-access request, or work-elevation request.
preview_contributor_request(request_type: str, rfp_id: str, requested_scope: str, message: str)#submit_contributor_request Verified identity
Submit a contributor request after verifying caller identity and write permission on BetterHackdays.
submit_contributor_request(request_type: str, rfp_id: str, requested_scope: str, message: str)#list_contributor_requests Verified identity
List private contributor requests for the verified requester or a verified BetterHackdays maintainer/admin.
list_contributor_requests()Permission guards
#authorize_github_mutation Verified identity
Verify authenticated human identity, exact repository permission, and Kenobi scope before any GitHub write.
authorize_github_mutation(operation: str, target_repo: str, expected_target_repo: Optional[str] = None)#grant_repository_access Preview only
Separate owner-only, explicitly confirmed repository access grant scoped to an allowlisted repository.
grant_repository_access(target_repo: str, grantee_login: str, permission: str = 'write', requester_login: Optional[str] = None, confirmed: bool = False)Hack Day room
#connect_harness
Connect a coding harness and create an active participant profile.
connect_harness(harness_id: str)#update_profile
Update profile fields used by matchmaking and planning.
update_profile(harness_id: str, display_label: Optional[str] = None, skills: Optional[list[str]] = None, interests: Optional[list[str]] = None, preferred_role: Optional[str] = None, project_vibe: Optional[str] = None, looking_for: Optional[list[str]] = None, availability: Optional[str] = None)#start_survey
Start or restart the Socratic onboarding survey.
start_survey(harness_id: str)#answer_survey
Record one onboarding survey answer.
answer_survey(harness_id: str, answer: str)#get_survey_state
Read survey progress without advancing it.
get_survey_state(harness_id: str)#get_match_cards
Return anonymized, scored candidate match cards.
get_match_cards(harness_id: str)#like_profile
Like a candidate and create a match when the like is mutual.
like_profile(from_harness_id: str, to_harness_id: str)#pass_profile
Pass on a candidate without creating a match.
pass_profile(from_harness_id: str, to_harness_id: str)#get_matches
Return open matches for a harness.
get_matches(harness_id: str)#ingest_event_text
Normalize pasted hackathon text into event context.
ingest_event_text(text: str, source_label: str = 'Pasted event text', source_url: str | None = None)#rank_idea_suggestions
Rank concise idea suggestions from event and team signals.
rank_idea_suggestions(event: Any, profile: Any = None, team: Optional[list[Any]] = None, topics: Optional[list[str]] = None)#generate_process_timeline
Generate a deadline-aware Hack Day execution timeline.
generate_process_timeline(event: Any, profile: Any = None, team: Optional[list[Any]] = None, hack_day: Any = None, team_room: Any = None, workspace_repo: Any = None)#generate_prep_checklist
Generate immediate prep tasks and first-hour focus.
generate_prep_checklist(event: Any, profile: Any = None, team: Optional[list[Any]] = None, hack_day: Any = None, team_room: Any = None, workspace_repo: Any = None)#resolve_slug
Resolve Hack Day codes, standalone slugs, and room keywords.
resolve_slug(raw_input: str, hack_days: list[dict[str, Any]], standalone_slugs: Optional[list[dict[str, Any]]] = None, caller_participant_id: Optional[str] = None)REST API
The REST routes call the same functions as the MCP tools. Routes marked Bearer token read your identity from an Authorization: Bearer header and nothing else.
28 routes served by app.main:app. Interactive docs run at /docs on any local server.
RFPs
| Method | Path | Auth |
|---|---|---|
| GET | /rfps | |
| GET | /rfps/search | |
| POST | /rfps/compare | |
| GET | /rfps/{rfp_id} |
Design resources
| Method | Path | Auth |
|---|---|---|
| GET | /design-resources | |
| GET | /design-resources/search | |
| POST | /design-resources/read |
Ideas
| Method | Path | Auth |
|---|---|---|
| GET | /ideas/catalogue | |
| POST | /ideas/qualify | |
| POST | /ideas/propose | Bearer token |
Contributor requests
| Method | Path | Auth |
|---|---|---|
| POST | /contributor/requests/preview | |
| POST | /contributor/requests/submit | Bearer token |
| POST | /contributor/requests/list | Bearer token |
Hack Day room
| Method | Path | Auth |
|---|---|---|
| GET | /health | |
| POST | /connect | |
| POST | /profile/update | |
| POST | /event/ingest/text | |
| POST | /planner/ideas | |
| POST | /planner/timeline | |
| POST | /planner/checklist | |
| POST | /slug/resolve | |
| GET | /matchmaking/cards | |
| POST | /matchmaking/like | |
| POST | /matchmaking/pass | |
| GET | /matches | |
| POST | /survey/start | |
| POST | /survey/answer | |
| GET | /survey/state |
08
Configuration
All settings are environment variables. Copy .env.example to .env for local runs. Everything is optional for reading.
| Variable | Default | Purpose |
|---|---|---|
DATABASE_URL | sqlite:///./betterhackdays.db | Local store for Hack Day state and private request records. |
GITHUB_TOKEN | unset | Your own GitHub token. Identifies you for submits and lists over MCP. |
KENOBI_GITHUB_TOKEN | unset | Maintainers only: KnowB GitHub App installation token for reviewed writes. |
SMTP_HOST, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, SMTP_FROM | unset, port 587 | Mail route for requests. Without it, submits return an unsent draft. |
APP_NAME | betterhackdays-matchmaking | Title of the REST app. |
SEED_PROFILES | true | Seeds demo profiles for the Hack Day room. |
09
Deploying this site
This manual is a Zola site in site/, published by GitHub Pages from the BetterHackdays repository to the custom domain hack.knowb.run. It has no tracking and no third-party scripts.
Writing docs
Every section of this page is a Markdown file in site/content/, ordered by weight. To add one, create a file with a title and a weight; it joins the index and search automatically. Components are shortcodes in site/templates/shortcodes/: alert, note, cards, minis, pipeline, route, guarantees, step, and faq.
zola --root site serve # live preview at http://127.0.0.1:1111
.venv/bin/python scripts/build_site.py # refresh the generated reference
Pipeline
- Check
build_site.py --checkOn every pull request, the docs test confirms
data/reference.jsonmatches the code. - Build
.github/workflows/pages.ymlInstalls Zola, checks the reference again, runs the docs tests against the built site, and builds
site/public. - Serve
hack.knowb.runOn a push to
main, GitHub Pages serves the build over HTTPS with a certificate it issues for the custom domain.
Custom domain setup
Done once, by a repository admin and the owner of the knowb.run DNS zone.
Enable Pages from Actions
Repository settings, Pages, Source: GitHub Actions. Or:
gh api -X POST repos/knowb-ai/BetterHackdays/pages -f build_type=workflowAdd the DNS record
At the
knowb.runDNS host:Type Host Answer CNAMEhackknowb-ai.github.ioSet the custom domain
Pages deployed by Actions ignore a
CNAMEfile, so set the domain in settings or with:gh api -X PUT repos/knowb-ai/BetterHackdays/pages -f cname=hack.knowb.runsite/static/CNAMEships with every build as a record of the intended domain.Enforce HTTPS
Once GitHub has issued the certificate, usually within an hour of DNS resolving:
gh api -X PUT repos/knowb-ai/BetterHackdays/pages -F https_enforced=trueVerify the domain
Verify
knowb.runfor theknowb-aiorganization under organization settings, Pages, so no other account can claimhack.knowb.run.
Verify a deployment
dig +short hack.knowb.run CNAME # knowb-ai.github.io.
curl -sI https://hack.knowb.run | head -1 # HTTP/2 200
gh api repos/knowb-ai/BetterHackdays/pages --jq '.cname, .https_enforced, .status'
Edit this section
10
FAQ
Do I need permission to read RFPs?
No. Listing, searching, reading, and comparing RFPs, reading design resources, and qualifying ideas need no account and no token.
I submitted an access request. Can I push now?
No. A request is not a grant. A repository owner reviews it, and only their explicit approval, sent as a GitHub invitation, gives you access.
Why does my submit say unauthorized?
The connector could not verify you. Check that GITHUB_TOKEN belongs to your own account and is current, and that your account has the permission the request type needs on BetterHackdays. Work elevation needs write or higher.
My submit came back “not sent”. Is that an error?
It means mail is not configured where the server runs. You get the full addressed draft so you can send it to ping@knowb.run yourself. The request is still recorded locally.
Why is the idea catalogue not on this site?
It has one home, Cloud Builder Stack, so it never drifts. The connector reads it live, and this page links to it.
Can I host my own connector?
Yes. It is a FastAPI app and a FastMCP server. Run it locally as shown in the quickstart, or anywhere Python runs. Requests still go to KnowB maintainers for review.
11
Contributing
BetterHackdays is developed in the open at knowb-ai/BetterHackdays. Issues and small, reviewable pull requests are welcome.
- Run the test suite before you open a pull request:
.venv/bin/python -m unittest discover -s tests -v. - If you change
README.md,agents.md, ordocs/*.md, update their OKF checksums and runpython scripts/validate_okf.py. - If you change the connector's tools or routes, run
python scripts/build_site.pyso this manual stays in step. - Use conventional commit prefixes:
feat:,fix:,chore:. - Read agents.md if an agent is working with you.
License
No license has been declared yet. Until one is, the code is public to read but not licensed for reuse. Ask at ping@knowb.run.
Security
Found a way around a permission check? Please email ping@knowb.run instead of opening a public issue.