Run ghfind locally, verify its HTTP surfaces, and provide controlled remote access
ghfind is an open-source developer discovery and GitHub profile scoring project with a browser interface, REST API, and MCP endpoint. The current repository is also a larger monorepo containing Go components, feed assets, database migrations, Dockerfiles, operational configuration, authentication-related features, and other services that are not fully covered by its basic local-development instructions. This tutorial therefore documents the narrower workflow that can be supported by the available evidence: start the Next.js development service with local D1 state, verify the browser, REST, OpenAPI, and MCP surfaces, then connect that working HTTP service to Localtonet. It does not claim that this procedure deploys every ghfind feature or constitutes a production architecture.
๐ What's in this guide
What this tutorial does and does not deploy
The ghfind repository describes an evidence-based platform for evaluating public GitHub profiles, discovering developers, and exposing scoring features programmatically. Its deterministic scoring model considers account maturity, original project quality, contribution quality, ecosystem impact, community influence, and activity authenticity. The project also evaluates farming-related warning signals intended to distinguish sustained engineering activity from easily inflated public metrics.
The score is calculated on the server from public GitHub data. The repository describes optional language-model processing as separate judge and writer passes. The judge may perform bounded calibration, while the writer generates report text and tags. The underlying deterministic scoring path does not require an LLM.
The basic upstream local-development instructions establish a pnpm-managed web workspace, a server-side GITHUB_TOKEN, Wrangler local D1 state, two D1 migration targets, and a pnpm dev startup command. Those instructions support a useful development deployment for testing the browser, REST, OpenAPI, and MCP routes served by that process.
The current repository contains more than the basic Next.js workflow. It includes Go source, backend and feed Dockerfiles, Compose configuration, feed migrations, operational assets, authentication-related functionality, and additional applications or packages. The supplied repository evidence does not establish which of those components must run for every feed, reaction, authentication, background-processing, GitHub App, or production scoring feature. This tutorial does not silently omit those services and then claim complete feature parity with ghfind.com.
In particular, a successful pnpm dev run proves only that the selected local development process started. A rendered home page proves even less. You must test each surface you intend to use. If your goal includes the public feed, authenticated profile reactions, GitHub App automation, production queues, scheduled work, or other features associated with the expanded monorepo, perform a separate architecture review against the exact revision you plan to deploy.
This revision also removes the former production-mode recommendation. Although the repository README may mention build or start workflows at different points in its history, the supplied audit evidence does not include the current package.json script definitions or confirm that a standalone pnpm start process can access Wrangler's local D1 emulator state. A successful Next.js build is not evidence that all database bindings, feed processes, authentication flows, or MCP behavior work in that mode. We therefore do not present pnpm build and pnpm start as a supported self-hosted deployment path here.
Understand the current ghfind component boundaries
The current repository is a monorepo rather than a single isolated web application. Its root includes directories such as apps, cmd, internal, packages, platform, src, migrations, migrations-feed, and ops. It also includes a Go module, backend and feed Dockerfiles, feed backup assets, a backend Compose file, Wrangler configuration, and pnpm workspace metadata.
Those files establish that broader deployment options and supporting components exist. They do not, by themselves, prove that every component is mandatory for the narrow development workflow. Conversely, the short README setup cannot be assumed to reproduce every capability represented by the larger repository. The safest approach is to distinguish directly tested surfaces from features that require a broader deployment review.
| Area | Repository evidence | Scope in this tutorial |
|---|---|---|
| Browser application | A Next.js web application is represented by the root package metadata, source tree, and Next.js configuration | Started with the documented development command and verified through an actual profile request |
| REST and OpenAPI | The project documents a score route and an OpenAPI 3.1 document | Verified directly against the running local web service |
| MCP | The project documents a Streamable HTTP endpoint at /mcp |
Verified with an MCP client, not by ordinary browser navigation |
| Primary D1 state | The local instructions apply migrations to a database named ghfind |
Initialized with Wrangler's --local mode |
| Feed D1 state | A second migration target named ghfind-feed-dev and a migrations-feed directory are present |
The schema is initialized, but this tutorial does not claim that every feed worker or background process is started |
| Go backend components | The repository includes go.mod, go.sum, cmd, and internal |
Not started by the narrow pnpm development procedure unless the reviewed revision explicitly wires them into that command |
| Container deployment | Backend, feed, and feed-backup Dockerfiles plus backend Compose configuration are present | Not documented here because the supplied evidence does not establish a complete, current container sequence and required secrets |
| Authentication and reactions | The public project description mentions GitHub-authenticated profile reactions | Not assumed to work from GITHUB_TOKEN alone; OAuth or GitHub App configuration must be audited separately |
| Optional Redis cache | The documented request flow marks Redis as optional | No Redis service is required by the basic workflow described here |
| Optional LLM reports | The project describes OpenAI-compatible judge and writer processing | Not configured unless the checked-out environment template declares and explains the required provider settings |
How a basic scoring request moves
In the documented web flow, the browser sends a request to a ghfind API route. The server retrieves public GitHub information through GitHub's REST and GraphQL interfaces using the operator's token, runs deterministic scoring logic, and may read or write cache and database state. Optional report generation follows separate model-backed processing.
The operator token remains server-side. A browser or API caller should not receive it. The caller communicates with ghfind, and ghfind communicates with GitHub. Localtonet forwards HTTP requests to ghfind; it does not need the GitHub token and should never be given that credential.
--local option.
Record and pin the exact ghfind revision
The upstream default branch can change at any time. Commands, workspace layout, environment variables, migration files, runtime requirements, and service boundaries can all drift after an article is published. The supplied audit snapshot identified the current main branch but did not include a commit SHA or release tag. We will not invent one or falsely label an unknown commit as tested.
Instead, record the exact commit before installation and keep that identifier with your deployment notes. The following sequence clones the repository, records the selected commit, and changes the checkout to detached mode so an ordinary pull cannot silently move the deployed source:
git clone https://github.com/hikariming/ghfind.git
cd ghfind
GHFIND_REVISION="$(git rev-parse HEAD)"
printf '%s\n' "$GHFIND_REVISION"
printf '%s\n' "$GHFIND_REVISION" > ../ghfind-deployment-revision.txt
git switch --detach "$GHFIND_REVISION"
git status --short
git rev-parse HEAD
Save the printed SHA. That SHA, rather than the word main, identifies the source you configured and tested. A clean git status --short produces no output. If it lists files before you begin, determine why the checkout differs from the recorded revision.
Recording a SHA makes your own run reproducible, but it does not mean this article has certified that commit for production. Validate the selected revision on your host, preserve its lockfile, inspect its package scripts and environment template, and test every surface you intend to expose.
To review a newer release later, create a separate checkout or branch, record the new SHA, and repeat installation, migration, and local verification. Do not replace a working public instance with an unreviewed moving branch.
Extract and verify the declared runtime requirements
You need Git, Node.js, pnpm, outbound HTTPS access to GitHub, writable local storage, and a GitHub personal access token. You also need the Localtonet client when you are ready to provide remote access.
The supplied repository extract does not show the values inside package.json, so it does not establish a specific Node.js version, pnpm version, or Corepack requirement. Stating version numbers without that evidence would be unsafe. After recording the commit, extract the constraints from that exact revision rather than relying on an unpinned web page:
git show HEAD:package.json
git show HEAD:pnpm-workspace.yaml
git show HEAD:.env.example
In package.json, look for an engines.node constraint, an engines.pnpm constraint, and a packageManager value. Also inspect the scripts object to confirm that the revision actually defines the dev command before running it.
If packageManager names a specific pnpm release and your Node.js installation includes Corepack, activate that declared package manager through your normal toolchain policy. Do not assume Corepack is required when the selected revision does not declare it. Likewise, the existence of pnpm-lock.yaml establishes pnpm usage, but it does not by itself establish an exact supported Node.js release.
Record the installed tool versions with the deployment revision:
git rev-parse HEAD
node --version
pnpm --version
corepack --version
If Corepack is not installed or not used by your environment, the last command may fail. That does not automatically invalidate the deployment. What matters is that the Node.js and pnpm versions satisfy the declarations in the pinned revision and can install its lockfile without rewriting it.
| Requirement | Purpose | Verification |
|---|---|---|
| Git | Retrieves, identifies, and pins the source revision | git --version and git rev-parse HEAD |
| Node.js | Runs the web application and JavaScript tooling | Compare node --version with the pinned package metadata |
| pnpm | Installs the workspace and invokes project scripts | Compare pnpm --version with packageManager or engine declarations |
| Corepack, if declared | Can provision the package-manager release named by the project | Use only when supported by your Node.js distribution and selected project revision |
| GitHub token | Allows server-side requests to GitHub APIs | Use a valid, minimally privileged token and keep it out of source control |
| Writable storage | Stores dependencies, build artifacts, and local D1 emulator state | Confirm the service account can write in the checkout |
| Localtonet client | Creates the outbound relay connection for remote HTTP access | Run it on the ghfind host for the simplest loopback target |
GitHub token planning
Create and manage the token using GitHub's personal access token guidance. Grant only the access required by the ghfind revision and features you are operating. The available ghfind evidence does not define one universal scope set for every browser, feed, authentication, GitHub App, and automation feature, so this article does not prescribe broad scopes.
The basic scoring workflow documents GITHUB_TOKEN. Other features may require additional settings from the pinned .env.example or service-specific documentation. Do not assume that an operator personal access token configures GitHub login, GitHub App installation, profile reactions, or feed services.
Install the web workspace and initialize local D1
These steps assume that you have cloned the repository, recorded its SHA, confirmed the runtime declarations, and kept the supplied lockfile. Run the commands from the repository root.
Install the pinned workspace dependencies
Use pnpm from the repository root. Do not delete or regenerate the lockfile merely to force installation through an incompatible toolchain.
Create the local environment file
Copy .env.example to .env.local, then review every variable declared by the pinned revision.
Set the server-side GitHub token
Assign the token to GITHUB_TOKEN locally. Configure other variables only when the pinned template explains their purpose and requirement.
Apply the primary local D1 migrations
Apply migrations to the local database named ghfind using Wrangler's local mode.
Apply the feed database migrations
Apply the documented migrations to ghfind-feed-dev. This initializes the schema but does not by itself prove that a separate feed service is running.
Start the development process
Run the documented development script and keep its terminal available while testing application behavior.
pnpm install
cp .env.example .env.local
On Windows PowerShell, use:
pnpm install
Copy-Item .env.example .env.local
Open .env.local in a local editor and replace the token placeholder:
GITHUB_TOKEN=your_github_token_here
Do not commit .env.local, place its contents in screenshots, paste it into support messages, or expose it through an HTTP route. If a token is committed or otherwise disclosed, revoke it through GitHub and create a replacement.
Apply both documented local migration targets in order:
pnpm exec wrangler d1 migrations apply ghfind --local
pnpm exec wrangler d1 migrations apply ghfind-feed-dev --local
The --local option selects Wrangler's local development state. The upstream instructions state that this local workflow does not connect to Cloudflare and does not require wrangler login. For general emulator behavior and the distinction between local and remote databases, consult Cloudflare's
D1 local development guidance.
Local D1 state is documented under:
.wrangler/state/v3
Start the development process:
pnpm dev
The documented local origin is http://localhost:3000. Read the terminal output from your pinned revision and resolve startup errors before continuing. Do not create a tunnel merely to see whether it fixes an application that is not listening locally.
Verify each supported surface locally
Local-first verification creates a clear boundary between ghfind problems and Localtonet configuration problems. Test only the surfaces you actually intend to use, but do not infer that one successful path proves all the others.
Test the browser and scoring path
Open:
http://localhost:3000
Confirm that the page renders, then submit a public GitHub username. Watch the terminal while the request runs. A static page load does not prove that the server can read GITHUB_TOKEN, reach GitHub, use its database bindings, or complete scoring.
Test the REST score route
The documented score path is /api/score/{username}. This example uses GitHub's public octocat account:
curl -i http://localhost:3000/api/score/octocat
Inspect the HTTP status, content type, and response body. Use the OpenAPI document from your running revision for the authoritative schema:
curl -i http://localhost:3000/openapi.json
The upstream hosted API reference is also available at ghfind's OpenAPI document, but a self-hosted integration should validate against the document served by its pinned local revision.
Test MCP with a compatible client
The documented local endpoint is:
http://localhost:3000/mcp
MCP over Streamable HTTP is a protocol endpoint. Opening it as an ordinary web page is not a complete test. Configure a compatible MCP client with the full URL, initialize the connection, discover the tools exposed by the running implementation, and invoke a non-destructive tool.
Tool names and schemas may change with the selected revision. Client and server behavior should follow the MCP Streamable HTTP transport specification supported by the versions you are using.
| Surface | Local address | Meaningful verification |
|---|---|---|
| Browser application | http://localhost:3000 |
Load the interface and complete a real public-profile request |
| REST score API | http://localhost:3000/api/score/{username} |
Inspect the HTTP status and structured response |
| OpenAPI document | http://localhost:3000/openapi.json |
Retrieve and validate the document served by the pinned revision |
| MCP server | http://localhost:3000/mcp |
Initialize with a compatible MCP client and discover or invoke a tool |
| Feed or authentication feature | Revision-dependent | Do not claim support until the required services, variables, callbacks, and migrations are independently established |
Expose the verified development service with Localtonet
Localtonet can expose the working HTTP service without inbound router port forwarding, firewall changes, a public IP address, or VPN setup. Our client creates an outbound connection to a Localtonet relay server. The tunnel remains available only while the selected client is connected and the tunnel is running.
Run our client on the ghfind host when possible. That arrangement allows the target to remain 127.0.0.1:3000. If the client runs on another machine, 127.0.0.1 would refer to that other machine, not the ghfind host. A remote-client arrangement also requires ghfind to listen on a network-reachable address, and that binding procedure is not established by the evidence used for this tutorial.
Follow the current Localtonet HTTP tunnel documentation and use the options currently shown for your account. The documented setup order is:
Install and run the Localtonet application
Install the client for the operating system on the machine running ghfind, then keep the client running.
Open the HTTP Tunnel page
Create the configuration in the HTTP tunnel area of the Localtonet dashboard.
Select the Process Type
Choose Random Sub Domain, Custom Sub Domain, or Custom Domain from the options available to your account. Each type serves the same target content at a public HTTPS address.
Select the AuthToken and server
Choose the device-specific token for the client running on the ghfind host and select a currently available relay server from the dashboard.
Enter the local target
For a same-host setup, use local IP 127.0.0.1 and port 3000.
Press Start
Creating the tunnel does not start it. Press Start, then use the assigned public HTTPS address for controlled testing.
Do not hardcode a relay server code from an old tutorial. Available values must come from the current dashboard. If you use a custom domain, check the current Localtonet documentation for its DNS requirements before changing records.
The documented score route does not require caller authentication, and this tutorial does not establish an authorization layer for the MCP endpoint. Do not leave either surface on an unrestricted public tunnel unless you have independently verified appropriate authentication and access controls. For the workflow documented here, the safe default is controlled, temporary tunnel use followed by stopping the tunnel.
Repeat the tests through the public origin
Start with the public root URL. If the browser workflow succeeds, append /api/score/octocat and inspect the response. Then configure your MCP client with the public /mcp URL and perform protocol-level initialization.
If all local paths work but every public path fails, examine the Localtonet client, selected AuthToken, relay selection, tunnel state, local IP, and port. If the public root works but a particular API route fails, the tunnel is reaching ghfind and the problem is more likely within the application route or one of its dependencies.
ghfind must continue listening locally, and the selected Localtonet client must remain connected with the tunnel started. Stopping either process makes the public endpoint unavailable. A saved tunnel configuration is not an active tunnel.
Security, data, and AGPL responsibilities
Internet reachability changes a development service's risk profile. Public callers may trigger GitHub API work through your operator token, consume host resources, exercise MCP tools, and interact with routes that were designed for a broader application architecture. A public HTTPS URL protects transport to the tunnel edge, but it does not turn an unauthenticated application route into an authorized one.
AGPL network-use note
The ghfind repository includes an AGPL license. The GNU Affero General Public License contains obligations that can be relevant when modified software is made available for users to interact with over a network. If you modify ghfind and operate it as a network service, review the exact license text for the revision you deploy and determine how to provide the corresponding source and notices required for your situation.
This is a practical reminder, not legal advice. License compliance can depend on what you changed, how you distribute or operate the software, and which components or dependencies are involved. Preserve copyright and license notices, document your deployed revision and modifications, and obtain qualified advice when the obligations are material to your organization.
The license link above follows the moving main branch for readability. For deployment records, replace main in that URL with the exact commit SHA you recorded so the license text is tied to the source revision you used.
Interpret scores responsibly
ghfind evaluates public GitHub signals. Private organizational work is not visible to the scoring engine, so the result represents a public footprint rather than a complete assessment of a person's ability or contribution quality. Use scores as one input, retain human review, and avoid treating automated output as proof about an individual.
Handle updates, migrations, and local state deliberately
Do not update an exposed checkout directly from a moving branch. Stop the Localtonet tunnel first, preserve the current revision identifier and required local state, and evaluate the new revision separately.
Stop public access and the application
Stop the Localtonet tunnel, then stop the foreground ghfind process before copying or changing local state.
Record the current deployment
Save the current commit SHA, runtime versions, environment variable names, and migration status without copying secret values.
Review the candidate revision
Inspect package scripts, runtime constraints, lockfile changes, environment-template differences, migration additions, Docker assets, and architecture changes.
Install and migrate the candidate separately
Use the package manager declared by the candidate revision and apply only its documented local migrations to an appropriate test state.
Repeat all local tests
Verify the browser, REST, OpenAPI, and MCP surfaces before restoring any remote access.
Restore controlled remote access
Start the tunnel only after the candidate behaves correctly and your access-control decision remains appropriate.
The local emulator state under .wrangler/state/v3 is operational data. The migration files in source control define schema changes, while the state directory contains the local database instance. One is not a substitute for the other.
The supplied project evidence does not define a production backup and restore policy for this local-development arrangement. If local records matter, stop processes before copying state, protect the copy as potentially sensitive data, and test restoration into a separate checkout. Do not call a file copy a reliable backup until you have successfully restored and verified it.
Troubleshoot one layer at a time
| Symptom | Likely layer | What to check |
|---|---|---|
| Node.js or pnpm is incompatible | Toolchain | Compare installed versions with the pinned revision's engines and packageManager declarations |
pnpm dev is missing |
Revision or package scripts | Confirm you are at the repository root and inspect the exact revision's scripts object |
| Dependency installation rewrites the lockfile | Package-manager mismatch | Stop and use the pnpm version declared by the pinned revision instead of accepting unexplained lockfile churn |
| D1 migration fails | Workspace or Wrangler | Run from the repository root, confirm installation succeeded, preserve the database names, and keep --local |
| The page loads but scoring fails | Environment or GitHub API | Confirm GITHUB_TOKEN is set, restart after changes, and inspect server output without printing the token |
| Feed or reaction features do not work | Incomplete architecture | Do not assume the web development process starts Go, feed, OAuth, GitHub App, or background components; audit the pinned revision's service documentation |
localhost:3000 refuses connections |
Application process | Confirm the development process remains running and use the address printed by that process |
| The MCP URL appears blank or rejects a browser request | Test method | Use a Streamable HTTP-compatible MCP client and perform protocol initialization |
| Local access works but the public URL fails | Localtonet | Check client connectivity, AuthToken selection, server selection, tunnel state, local IP, and port |
| The public root works but an API path fails | Application route | Repeat the same request locally and inspect ghfind logs, HTTP status, GitHub access, and database state |
| Data disappears after moving the checkout | Local D1 state | Confirm whether .wrangler/state/v3 was preserved and whether migrations were applied in the new location |
Use this diagnostic order
First confirm the recorded source revision and runtime versions. Next confirm that dependency installation completed without unexpected lockfile changes. Then check both migration commands. Start ghfind and test the root page locally, followed by REST, OpenAPI, and MCP.
Investigate Localtonet only after those local checks pass. Confirm that our client is connected, that the correct device-specific AuthToken is selected, that the tunnel has been started, and that the target is 127.0.0.1:3000. Change one layer at a time and repeat the smallest relevant test after each change.
Frequently asked questions
Is this a complete production self-hosting guide for every ghfind feature?
No. It is a pinned, local-development workflow for the documented web process and local D1 migrations. The expanded repository includes Go, feed, container, authentication, backup, and operational components whose complete deployment relationships were not established by the supplied evidence.
Why does the tutorial not recommend pnpm build and pnpm start?
The available audit evidence does not include current script definitions or prove that a standalone start process receives the same local D1 bindings and supports every described surface. A successful Next.js build alone is not sufficient evidence of a complete self-hosted runtime.
Does local D1 development require a Cloudflare login?
No. The documented local workflow uses Wrangler's local D1 emulator and keeps --local on both migration commands. It does not require wrangler login.
Where is the local D1 state stored?
The upstream development instructions identify .wrangler/state/v3. Preserve and protect that directory if your local records matter, and test any restoration procedure before relying on it.
Is an LLM required for the deterministic score?
No. The base score is deterministic. Optional model-backed judge and writer passes are separate. Configure them only through settings documented by your pinned revision.
Can one Localtonet tunnel carry the browser, REST, OpenAPI, and MCP paths?
Yes, when those paths are served by the same verified local HTTP process. The tunnel forwards the public origin to 127.0.0.1:3000, and the request paths remain part of that origin.
Does Localtonet add authentication to the ghfind API or MCP endpoint?
No. An HTTP tunnel provides reachability. It does not automatically add application authorization. Keep unauthenticated REST and MCP surfaces off a persistent public tunnel unless you have independently verified suitable access controls.
Why must I record a commit SHA?
A SHA identifies the exact source, package scripts, lockfile, migration files, and environment template you tested. A moving branch name such as main cannot provide the same reproducibility.
Does operating modified ghfind over a network have license implications?
Potentially. ghfind is AGPL-licensed, and the license includes provisions relevant to interaction with modified software over a network. Review the license tied to your exact revision and obtain legal advice when needed.
Provide controlled access to your verified ghfind development service
After the browser, REST, OpenAPI, and MCP checks pass on localhost:3000, create a Localtonet HTTP tunnel for a controlled test window without configuring inbound router port forwarding.