Add a maintainer's guide (#356)
diff --git a/README.md b/README.md
index 0eb832f..58e0878 100644
--- a/README.md
+++ b/README.md
@@ -119,3 +119,8 @@
then you probably forgot to load and call `bazel_skylib_workspace()` in your
`WORKSPACE` file.
+
+### Maintainer's guide
+
+See the [maintaner's guide](docs/maintainers_guide.md) for instructions for
+cutting a new release.
diff --git a/docs/maintainers_guide.md b/docs/maintainers_guide.md
new file mode 100644
index 0000000..8a009c2
--- /dev/null
+++ b/docs/maintainers_guide.md
@@ -0,0 +1,114 @@
+# Skylib Maintainer's Guide
+
+## The Parts of Skylib
+
+* `bzl_library.bzl` - used by almost all rule sets, and thus requiring
+ especial attention to maintaining backwards compatibility. Ideally, it ought
+ to be moved out of Skylib and and into Bazel's bundled `@bazel_tools` repo
+ (see https://github.com/bazelbuild/bazel-skylib/issues/127).
+* Test libraries - `rules/analysis_test.bzl`, `rules/build_test.bzl`,
+ `lib/unittest.bzl`; these are under more active development than the rest of
+ Skylib, because we want to provide rule authors with a good testing story.
+ Ideally, these ought to be moved out of Skylib and evolved at a faster pace.
+* A kitchen sink of utility modules (everything else). Formerly, these
+ features were piled on in a rather haphazard manner. For any new additions,
+ we want to be more conservative: add a feature only if it is widely needed
+ (or was already independently implemented in multiple rule sets), if the
+ interface is unimpeachable, if level of abstraction is not shallow, and the
+ implementation is efficient.
+
+## PR Review Standards
+
+Because Skylib is so widely used, breaking backwards compatibility can cause
+widespread pain, and shouldn't be done lightly. Therefore:
+
+1. In the first place, avoid adding insufficiently thought out, insufficiently
+ tested features which will later need to be replaced in a
+ backwards-incompatible manner. See the criteria in README.md.
+2. Given a choice between breaking backwards compatibilty and keeping it, try
+ to keep backwards compatibility. For example, if adding a new argument to a
+ function, add it to the end of the argument list, so that existing callers'
+ positional arguments continue to work.
+3. Keep Skylib out-of-the-box compatible with the current stable Bazel release
+ (ideally - with two most recent stable releases).
+ * For example, when adding a new function which calls the new
+ `native.foobar()` method which was introduced in the latest Bazel
+ pre-release or is gated behind an `--incompatible` flag, use an `if
+ hasattr(native, "foobar")` check to keep the rest of your module (which
+ doesn't need `native.foobar()`) working even when `native.foobar()` is
+ not available.
+
+In addition, make sure that new code is documented and tested.
+
+If a PR adds or changes any docstrings, check that Markdown docs in `docs`
+directory are updated; if not, ask the PR author to run
+`./docs/regenerate_docs.sh`. (See
+https://github.com/bazelbuild/bazel-skylib/pull/321 for the proposal to automate
+this.)
+
+## Making a New Release
+
+1. Update CHANGELOG.md at the top. You may want to use the following template:
+
+--------------------------------------------------------------------------------
+
+Release $VERSION
+
+**New Features**
+
+- Feature
+- Feature
+
+**Incompatible Changes**
+
+- Change
+- Change
+
+**Contributors**
+
+Name 1, Name 2, Name 3 (alphabetically from `git log`)
+
+--------------------------------------------------------------------------------
+
+2. Bump `version` in version.bzl to the new version.
+3. Ensure that the commits for steps 1 and 2 have been merged. All further
+ steps must be performed on a single, known-good git commit.
+4. `bazel build //distribution:bazel-skylib-$VERSION.tar.gz`
+5. Copy the `bazel-skylib-$VERSION.tar.gz` tarball to the mirror (you'll need
+ Bazel developer gcloud credentials; assuming you are a Bazel developer, you
+ can obtain them via `gcloud init`):
+
+```
+gsutil cp bazel-bin/distro/bazel-skylib-$VERSION.tar.gz gs://bazel-mirror/github.com/bazelbuild/bazel-skylib/releases/download/$VERSION/bazel-skylib-$VERSION.tar.gz
+gsutil setmeta -h "Cache-Control: public, max-age=31536000" "gs://bazel-mirror/github.com/bazelbuild/bazel-skylib/releases/download/$VERSION/bazel-skylib-$VERSION.tar.gz"
+```
+
+6. Run `sha256sum bazel-bin/distro/bazel-skylib-$VERSION.tar.gz`; you'll need
+ the checksum for the release notes.
+7. Draft a new release with a new tag named $VERSION in github. Attach
+ `bazel-skylib-$VERSION.tar.gz` to the release. For the release notes, use
+ the CHANGELOG.md entry plus the following template:
+
+--------------------------------------------------------------------------------
+
+**WORKSPACE setup**
+
+```
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+http_archive(
+ name = "bazel_skylib",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/$VERSION/bazel-skylib-$VERSION.tar.gz",
+ "https://github.com/bazelbuild/bazel-skylib/releases/download/$VERSION/bazel-skylib-$VERSION.tar.gz",
+ ],
+ sha256 = "$SHA256SUM",
+)
+load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+bazel_skylib_workspace()
+```
+
+**Using the rules**
+
+See [the source](https://github.com/bazelbuild/bazel-skylib/tree/$VERSION).
+
+--------------------------------------------------------------------------------
\ No newline at end of file