{"id":28534966,"url":"https://github.com/vsco/dcdr","last_synced_at":"2026-06-10T01:01:04.775Z","repository":{"id":47697433,"uuid":"49972788","full_name":"vsco/dcdr","owner":"vsco","description":"Decider: Distributed Feature Flags ","archived":false,"fork":false,"pushed_at":"2026-06-09T01:57:10.000Z","size":1885,"stargazers_count":179,"open_issues_count":4,"forks_count":12,"subscribers_count":51,"default_branch":"master","last_synced_at":"2026-06-09T02:25:59.401Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vsco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-01-19T18:14:19.000Z","updated_at":"2025-12-13T23:29:53.000Z","dependencies_parsed_at":"2024-06-20T16:30:17.315Z","dependency_job_id":"b8225404-9956-44b0-a1ef-18fca98210f3","html_url":"https://github.com/vsco/dcdr","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/vsco/dcdr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsco%2Fdcdr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsco%2Fdcdr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsco%2Fdcdr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsco%2Fdcdr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vsco","download_url":"https://codeload.github.com/vsco/dcdr/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vsco%2Fdcdr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34132030,"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-09T02:00:06.510Z","response_time":63,"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":"2025-06-09T17:13:34.281Z","updated_at":"2026-06-10T01:01:04.766Z","avatar_url":"https://github.com/vsco.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/vsco/dcdr.svg?branch=master)](https://travis-ci.org/vsco/dcdr)\n\n# dcdr (decider)\nDistributed Feature Flags\n\n## Pre-Release\n\nThis is pre-release software. The Consul backend support has been used in production at VSCO for a year.\n\nAs of version 0.4.0-rc0, the etcd backend is no longer supported.\n\n## Overview\n\nDecider is a [feature flag](https://en.wikipedia.org/wiki/Feature_toggle) system with adaptable backends. It supports both `percentile` and `boolean` flags for controlled infrastructure rollouts and kill switches. Decider is built to be adaptable to any backing datastore. At the moment, [Consul](https://www.consul.io/intro/getting-started/kv.html) and [Redis](http://redis.io/) are supported.\n\nDecider has four major components.\n\n* [`Client`](#using-the-go-client) for use within your Go applications\n* [`Server`](#decider-server) for accessing features over HTTP\n* [`Watcher`](#starting-the-watcher) observes change in the datastore and writes them to disk\n* [`CLI`](#cli) for managing features, watches, and starting the server\n\nEach of these components are comprised of lower level libraries that you can use to suit your system's specific needs.\n\n### About Feature Flags\n\nFeature flags have many use cases and there are many implementations. With Decider, the three supported types of flags are `boolean`, `percentile`, and `scalar`. For our purposes at [VSCO](http://vsco.co), these have been enough to handle our needs.\n\n#### Boolean Flags\nAn example use case for a `boolean` flag would be an API kill switch that could alleviate load for a backing database.\n\n```\ndisable-load-heavy-api-endpoint =\u003e true\n```\n\nYour code would look something like this.\n\n```Go\nif dcdr.IsAvailable(\"disable-load-heavy-api-endpoint\") {\n\t// DB is having a bad day, please check back later\n} else {\n\t// All good, go about your day\n}\n```\n\n#### Percentile Flags\nPercentiles work much the same way but allow you to stress features or new infrastructure with a percentage of the request volume.\n\nA common use case for `percentile` features would be testing out a new backend store with dual write percentage.\n\n```\nrollout-new-fancy-db-dual-write =\u003e 0.1\n```\n\n```Go\n// Handle the write to the existing store\n\nif dcdr.IsAvailableForID(\"rollout-new-fancy-db-dual-write\", user.Id) {\n\t// If the `user.Id` falls into 10% of requests do the dual write\n}\n```\n\n#### Scalars\nPercentiles have an added bonus: you may use their `float64` values as scalars in certain cases.\n\nHere, we'll use the float value to scale the wait time for DB inserts between 0-1000ms.\n\n```\n daemon-db-insert-wait-ms =\u003e 0.1\n```\n\n```Go\n// waitMS would be 1000*0.1 =\u003e 100\nwaitMS := dcdr.ScaleValue(\"daemon-db-insert-wait-ms\", 0, 1000)\ntime.Sleep(waitMS * time.Millisecond)\n```\n\n[Read more](#using-the-go-client) on how to use the `Client`.\n\n### Caveat\n\nFeature flags and remote configuration are hard problems to solve in the general sense. Most organizations will have many corner cases unique to their own infrastructure and policies that are cumbersome to solve in an abstract way. Decider is an extracted set of flexible libraries that we at [VSCO](http://vsco.co) have developed over the past year that have worked well for us in solving these issues.\n\nThis package does not set out to provide features like authentication or ACLs, but it does aim to provide enough of the tooling and libraries so that you can do so yourself.\n\n### Scopes\nIn order to allow for expanding use cases and to avoid naming collisions, Decider provides arbitrary scoping of feature flags. An example use case would be providing separate features sets according to country code or mobile platform. Additionally, multiple Decider instances can be run within a cluster with separate namespaces and key sets by configuring [`config.hcl`](#configuration).\n\n### Audit Trail\nDue to the sensitive nature of configuration management, knowing the who, what, and when of changes can be very important. Decider uses `git` to handle this responsibility. By easily specifying a `git` repository and its origin in [`config.hcl`](#configuration), Decider will export your keyspace as a `JSON` file and then commit and push the changeset to the specified origin. Of course, this is all optional if you enjoy living dangerously.\n\n![](./resources/repo.png)\n\n### Observabilty\nIt's nice to know when changes are happening. Decider can be configured to emit [Statsd](https://github.com/etsy/statsd) events when changes occur. Custom event tags can be sent as well if your collector supports them. Included in this package is a [DataDog](https://www.datadoghq.com/) adapter with Event and Tag support. Custom stats can also be configured by supplying a custom `stats.IFace` implementation.\n\n## Installation\n\n* Install via `go get`\n\t* \t`go get -a github.com/vsco/dcdr`\n* Install via release\n\t*  [https://github.com/vsco/dcdr/releases](https://github.com/vsco/dcdr/releases)\n* Build from source\n\n```\ngit clone git@github.com:vsco/dcdr.git\ncd dcdr\nscript/bootstrap\nscript/install\n```\n\n## Getting Started\n\n### CLI\nThe `dcdr` CLI has comprehensive help system for all commands.\n\n```bash\ndcdr help [command]\" for more information about a command.\n```\n\n### Setting Features\n\nFeatures have several fields that are accessible via `set` command.\n\n```bash\n\t-n, --name=\"flag_name\"\n\t\tthe name of the flag to set\n\t-v, --value=0.0-1.0 or true|false\n\t\tthe value of the flag\n\t-c, --comment=\"flag description\"\n\t\tan optional comment or description\n\t-s, --scope=\"users/beta\"\n\t\tan optional scope to nest the flag within\n```\n\n#### Example\n\n```bash\ndcdr set -n new-feature -v 0.1 -c \"some new feature\" -s user-groups/beta\n```\n\nThe above command sets the key `dcdr/features/user-groups/beta/new-feature` equal to `0.1` and commits the update to the audit repo.\n\n![](./resources/set.png)\n\n### Listing Features\n\nListing features can be filtered by a given `scope` and `prefix`. Any further fanciness can be handled by piping the output to `grep` or `less`.\n\n```bash\n\t-p, --prefix=\"\u003cflag-prefix\u003e\"\n\t\tList only flags with matching prefix.\n\t-s, --scope=\"\u003cflag-scope\u003e\"\n\t\tList only flags within a scope.\n```\n\n#### Example\n\n```bash\ndcdr list -p new -s user-groups/beta\n```\n\n![](./resources/list.png)\n\n### Deleting Features\n\nFeatures are removed using the `dcdr delete` command and take a `name` and `scope` parameters. If no `scope` is provided the `default` scope is assumed. Once deleted and if you have a repository configured, Decider will commit the changeset and push it to origin.\n\n```\n\t-p, --prefix=\"\u003cflag-prefix\u003e\"\n\t\tName of the flag to delete\n\t-s, --scope=\"\u003cflag-scope\u003e\"\n\t\tOptional scope to delete the flag from\n```\n\n#### Example\n\n```\ndcdr delete -n another-feature -s user-groups/beta\n```\n\n![](./resources/delete.png)\n\n### Starting the Watcher\n\nThe `watch` command is central to how Decider features are distributed to nodes in a cluster. It observes the configured namespace and writes a `JSON` file containing the exported structure to the [`Server:OutputPath`](#configuration).\n\nBy default the Decider configuration and watch path are located in `/etc/dcdr`. If this path does not exist you will need to create it.\n\n```\n sudo mkdir /etc/dcdr\n sudo chown `whoami` /etc/dcdr\n```\n\nYou can override this location by setting the `DCDR_CONFIG_DIR` environment variable. More on configuration can be found [here](#configuration).\n\n![](./resources/watch.png)\n\n## Tying the room together\n\n### TL;DR Using Docker Compose\n\nDecider has many moving parts that require orchestration in order to do a proper demonstration of how they all work together.\nSo thanks to [Docker Compose](https://docs.docker.com/compose/) we can bundle this up quite easily. This example uses a\nConsul backend and starts a `dcdr watch` and `dcdr server` for you.\n\n#### Building \u0026 running the images\n\n```bash\n./script/compose\n```\n\nThis starts a Consul agent for the backend, a Decider server, and a Decider Watcher.\n\n![](./resources/compose.png)\n\nWith these services running you can now interact with the `dcdr` CLI via\n`docker-compose exec` from another terminal window through the `dcdr_server`\ncontainer.\n\ncommand to add/modify a feature flag:\n```bash\n$ docker-compose exec dcdr_server dcdr set -n feat-foo -v true\n[dcdr] set flag 'dcdr/features/default/feat-foo'\n```\n\nresult logs from running docker-compose log:\n```bash\ndcdr_watch_1   | [dcdr] 2018/03/13 18:25:48 wrote changes to: /etc/dcdr/decider.json\n```\n\ncommand to fetch feature flags from Decider server API:\n```bash\n$ docker-compose exec dcdr_server curl 127.0.0.1:8000/dcdr.json\n{\n  \"dcdr\": {\n    \"info\": {},\n    \"features\": {\n      \"feat-foo\": true\n    }\n  }\n}\n```\n\nresult logs from running docker-compose log:\n```bash\ndcdr_server_1  | 127.0.0.1 - - [13/Mar/2018:18:36:51 +0000] \"GET /dcdr.json HTTP/1.1\" 200 102 \"\" \"curl/7.52.1\"\n```\n\n![](./resources/compose-commands.png)\n\nNow you can update features, CURL the results from the server, and see the changes update in realtime.\n\n### From Scratch\nThis example uses the Consul backend. If you need instructions for getting Consul installed, check their [Getting Started](https://www.consul.io/intro/getting-started/install.html) page.\n\nLet's start a development `consul agent` with an empty feature set and see how this all works together. For simplicity we can use the default Decider configuration without a git repository or stats.\n\n```\nconsul agent -bind \"127.0.0.1\" -dev\n```\n\nThis will start a local Consul agent ready to accept connections on `http://127.0.0.1:8500`. Decider should now be able to connect to this instance and set features.\n\n#### Set some features\n\n```\n# check that we can talk to the local agent\n~  → dcdr list\n[dcdr] no feature flags found in namespace: dcdr\n\n# set a feature into the 'default' scope.\n~  → dcdr set -n example-feature -v false\n[dcdr] set flag 'dcdr/features/default/example-feature'\n\n# set a feature into the 'user-groups/beta' scope.\n~  → dcdr set -n example-feature -v true -s user-groups/beta\n[dcdr] set flag 'dcdr/features/user-groups/beta/example-feature'\n\n~  → dcdr list\n\nName             Type     Value  Comment  Scope             Updated By\nexample-feature  boolean  false           default           chrisb\nexample-feature  boolean  true            user-groups/beta  chrisb\n```\nHere we have set the feature `example-feature` into two separate scopes. In the 'default' scope the value is `false` and in the 'user-groups/beta' scope it has been set to true.\n\n##### Start the watcher and observe changes\n\n```\n# start the watcher\n~  → dcdr watch\n[dcdr] 2016/03/09 17:56:17.250948 watching namespace: dcdr\n[dcdr] 2016/03/09 17:56:17.365362 wrote changes to /etc/dcdr/decider.json\n```\n\nThe watcher is now observing your \u0026laquo;Namespace\u0026raquo; and writing all changes to the [`Server:OutputPath`](#configuration) default `/etc/dcdr/decider.json`.\n\n### Decider Server\nThe easiest way to view your feature flags is with `dcdr server`. This is a bare bones implementation of how to access features over HTTP. There is no authentication, so unless your use case is for internal access only you should include the `server` package into a new project and assemble your own. The server is built with [gorilla/mux](https://github.com/gorilla/mux) router and is extensible by adding additional middleware. Read more on custom servers [here](#building-a-custom-server).\n\n```\n# start the server\n~  → dcdr server\n[dcdr] started watching /etc/dcdr/decider.json\n[dcdr] 2016/03/09 18:03:46.211150 serving /dcdr.json on :8000\n```\nThe server is now running on `:8000` and features can be accessed by curling `:8000/dcdr.json`. In order to access your scopes the server accepts a `x-dcdr-scopes` header. This is a comma-delimited, priority-ordered list of scopes. Meaning that the scopes should provided with the highest priority first. For now we only have one scope so let's start simple.\n\n```\n# curl with no scopes\n~  → curl -s :8000/dcdr.json\n{\n  \"info\": {},\n  \"dcdr\": {\n    \"example-feature\": false\n  }\n}\n```\nHere we see that the default value of false is returned. The `info` key is where information like the current SHA of the repository would be if one was configured. Next, if we add the scope header we can access our scoped values.\n```\n~  → curl -sH \"x-dcdr-scopes: user-groups/beta\" :8000/dcdr.json\n{\n  \"dcdr\": {\n    \"info\": {},\n    \"features\": {\n      \"example-feature\": true\n    }\n  }\n}\n```\n\n## Using the Go client\n\nIncluded in this package is a Go client. By default this client uses the same [`config.hcl`](#configuration) for its configuration. You may also provide custom your own custom configuration as well using `config.Config` and the `client.New` method. For this example we will assume the defaults are still in place and that the features from the above example have been set.\n\n### Require and initialize the client\n\n```Go\nimport \"github.com/vsco/dcdr/client\"\n\n// Initialize a client with the default configuration\nclient, err := client.NewDefault()\n\nif err != nil {\n\tpanic(err)\n}\n```\n\n### Checking feature flags\n\nThe client has three main methods for interacting with flags `IsAvailable(feature string)`. `IsAvailableForID(feature string, id uint64)`, and `ScaleValue(feature string, min float64, max float64)`.\n\n#### IsAvailable\n\nThis method is for checking `boolean` features or 'kill switches'. If a `percentile` feature is passed to this method it will always return false. So don't do that.\n\n```\n# set the default feature\ndcdr set -n example-feature -v false\n```\n\n```Go\nclient, err := client.NewDefault()\n\nif err != nil {\n\tpanic(err)\n}\n\n// example-feature would be false\nif client.IsAvailable(\"example-feature\") {\n\tfmt.Println(\"example-feature enabled\")\n} else {\n\tfmt.Println(\"example-feature disabled\")\n}\n```\n\nThis example initializes a new `Client` and begins watching the 'default' feature scope. It then checks the `example-feature` and runs the appropriate code path given the current value of the feature.\n\n#### So what about scopes?\n\nTo initialize a Decider `Client` into a given set of scopes use the `WithScopes(scopes ...string)` method. This method creates a new `Client` with an underlying feature set that has the provided `scope` values merged onto the default set. If a feature does not exist in any of the provided scopes the client will fallback to the 'default' `scope` to find the value. If the feature does not exist in any scope the client simply returns `false`.\n\n```\n# set the scoped feature\ndcdr set -n example-feature -v true -s user-groups/beta\n```\n\n```Go\nclient, err := client.NewDefault()\nscopedClient := client.WithScopes(\"user-groups/beta\")\n\nif err != nil {\n\tpanic(err)\n}\n\n// example-feature would be true\nif scopedClient.IsAvailable(\"example-feature\") {\n\tfmt.Println(\"example-feature enabled\")\n} else {\n\tfmt.Println(\"example-feature disabled\")\n}\n```\n\n#### Fallbacks\n\n```\n# set a feature that does not exist in user-groups/beta\ndcdr set -n another-feature -v true\n```\n\n```Go\nclient, err := client.NewDefault()\nscopedClient := client.WithScopes(\"user-groups/beta\")\n\nif err != nil {\n\tpanic(err)\n}\n\n// another-feature would be true\nif scopedClient.IsAvailable(\"another-feature\") {\n\tfmt.Println(\"another-feature enabled\")\n} else {\n\tfmt.Println(\"another-feature disabled\")\n}\n```\n\n### IsAvailableForID\n\nThis method is used when a feature needs to be rolled out to only a percentage of requests. Functionally `IsAvailableForID` works exactly as `IsAvailable` with the exception of its `id` argument. Both the `feature` and `id` arguments are joined to generate a `uint64` using `hash/crc32`. Which when combined with the `float64` value of `feature` can compute into what percentile a given request falls.\n\nSee the [`Client#withinPercentile`](https://github.com/vsco/dcdr/blob/master/client/client.go#L224) method for more details.\n\n#### Using percentiles\n\n```\n# set a feature to 50%\ndcdr set -n new-feature-rollout -v 0.5\n```\n\n```Go\nclient, err := client.NewDefault()\n\nif err != nil {\n\tpanic(err)\n}\n\nuserId := unint64(5)\n\n// new-feature-rollout would be true\nif client.IsAvailableForID(\"new-feature-rollout\", userId) {\n\tfmt.Println(\"new-feature-rollout enabled\")\n} else {\n\tfmt.Println(\"new-feature-rollout disabled\")\n}\n```\n\n### ScaleValue\n\n`ScaleValue` uses the same `float64` values as `IsAvailableForID` but in this case these values are used to obtain a new value scaled between a `min` and a `max`.\n\nFor instance:\n\nGiven the feature `db-insert-wait-ms =\u003e 0.5`. When provided to the `ScaleValue` method would result in the following.\n\n```Go\nfor {\n\tinsertWaitMs := dcdr.ScaleValue(\"db-insert-wait-ms\", 0, 1000)\n\ttime.Sleep(insertWaitMs * time.Millisecond) // waits for 500ms\n\n\tdb.Insert(\"some-value\")\n}\n```\n\n## Building a custom Server\n\nExposing your feature flags to the open internet would be a terrible idea in most cases. The default server will work fine as long as access is restricted to internal network clients but what if we want to allow access to mobile devices? Since there are entirely too many auth strategies to cover and we are kind of lazy, Decider `Server` allows you to add middleware to customize its behavior to suit your authentication needs.\n\n### Extending with middleware\n\nBelow is an example of how to do authentication very poorly. However, if you look close enough you can imagine exactly where you might add a DB lookup for an OAuth token or something similar. The `Use` method takes variadic `server.Middleware` as a param to allow chainable customizations.\n\n```Go\n// Middleware helper type for handlers that receive a `Client`.\ntype Middleware func(client.IFace) func(http.Handler) http.Handler\n```\n\n```Go\nconst AuthorizationHeader = \"Authorization\"\n\n// MockAuth example authentication middleware.\n// Checks for any value in the http Authorization header.\n// If no value is found a 401 status is sent.\nfunc MockAuth(c client.IFace) func(http.Handler) http.Handler {\n  return func(h http.Handler) http.Handler {\n    fn := func(w http.ResponseWriter, r *http.Request) {\n      if r.Header.Get(AuthorizationHeader) != \"\" {\n        h.ServeHTTP(w, r)\n      } else {\n         w.WriteHeader(http.StatusUnauthorized)\n      }\n    }\n    return http.HandlerFunc(fn)\n  }\n}\n\nfunc main() {\n\t// Create a new Server and Client\n\tsrv, err := server.NewDefault()\n\n    if err != nil {\n      panic(err)\n    }\n\n\t// Add the MockAuth to the middleware chain\n\tsrv.Use(MockAuth)\n\n\t// Begin serving on :8000\n\t// curl -sH \"Authorization: authorized\" :8000/dcdr.json\n\tsrv.Serve()\n}\n```\n\nHere is a bit more useful example. This `ScopedCountryCode` middleware takes the `X-Country` header and appends it to `x-dcdr-scopes`. We then use the `country-code/\u003ccc\u003e` scope to look up per country feature flags from the K/V store.\n\n```Go\nconst CountryCodeHeader = \"X-Country\"\nconst DcdrScopesHeader = \"x-dcdr-scopes\"\n\nfunc ScopedCountryCode(c client.IFace) func(http.Handler) http.Handler {\n\treturn func(h http.Handler) http.Handler {\n\t\tfn := func(w http.ResponseWriter, r *http.Request) {\n\t\t\tcc := strings.ToLower(r.Header.Get(CountryCodeHeader))\n\n\t\t\tif cc != \"\" {\n\t\t\t\t// Check for existing scopes and append 'country-code/xx'\n\t\t\t\tscopes := strings.Split(r.Header.Get(DcdrScopesHeader), \",\")\n\t\t\t\tscopes = append(scopes, fmt.Sprintf(\"country-codes/%s\", cc))\n\t\t\t\tr.Header.Set(DcdrScopesHeader, strings.Join(scopes, \",\"))\n\t\t\t}\n\n\t\t\th.ServeHTTP(w, r)\n\t\t}\n\n\t\treturn http.HandlerFunc(fn)\n\t}\n}\n```\n\nA full working example can be found in [server/demo/main.go](https://github.com/vsco/dcdr/blob/master/server/demo/main.go).\n\n## Configuration\n\nAll configuration lives in `config.hcl`. By default Decider looks for this file in `/etc/dcdr/config.hcl`. You will need to create the `/etc/dcdr` directory. Your permissions depending on the machine may differ but to get started locally do the following.\n\n```\n sudo mkdir /etc/dcdr\n sudo chown `whoami` /etc/dcdr\n dcdr init\n```\n\nThe default config path can also be overriden by setting the `DCDR_CONFIG_PATH` environment variable to a location of your choosing.\n\nRunning `dcdr init` will create a default config file for you if one does not already exist. Once you have edited this file with your, statsd, and git repo configurations you can view this info by running the `dcdr info` command.\n\nTo create a new repository from scratch. Configure the `config.hcl` file with your `RepoPath` and `RepoURL` and then run `dcdr init --create`. This will create the repo add an empty `JSON` file and attempt to push it to the specified origin.\n\n![](./resources/info.png)\n\n### Example config.hcl\n\n```\nUsername = \"twoism\"\nNamespace = \"dcdr\"\n\nStorage = \"consul\" // redis\n\nConsul {\n  Address = \"127.0.0.1:8500\"\n}\n\n//Redis {\n//  Address = \":6379\"\n//}\n\nWatcher {\n  OutputPath = \"/etc/dcdr/decider.json\"\n}\n\nServer {\n  JsonRoot = \"dcdr\"\n  Endpoint = \"/dcdr.json\"\n}\n\nGit {\n  RepoURL = \"git@github.com:vsco/decider-test-config.git\"\n  RepoPath = \"/etc/dcdr/audit\"\n}\n\nStats {\n  Namespace = \"dcdr\"\n  Host = \"127.0.0.1\"\n  Port = 8126\n}\n```\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvsco%2Fdcdr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvsco%2Fdcdr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvsco%2Fdcdr/lists"}