diff --git a/.clang-format b/.clang-format
index 5ec78a2f0665..21f2150afcec 100644
--- a/.clang-format
+++ b/.clang-format
@@ -23,4 +23,3 @@ AlignAfterOpenBracket: true
BinPackArguments : false
AlignOperands : true
BreakBeforeTernaryOperators : true
-AllowAllParametersOfDeclarationOnNextLine : false
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 000000000000..84ef7023736f
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,40 @@
+FROM fluxrm/testenv:focal
+
+LABEL maintainer="Vanessasaurus <@vsoch>"
+
+# Match the default user id for a single system so we aren't root
+ARG USERNAME=vscode
+ARG USER_UID=1000
+ARG USER_GID=1000
+ENV USERNAME=${USERNAME}
+ENV USER_UID=${USER_UID}
+ENV USER_GID=${USER_GID}
+
+# Pip not provided in this version
+RUN apt-get update
+COPY scripts/requirements-dev.txt /requirements.txt
+
+# For easier Python development.
+RUN python3 -m pip install IPython && \
+ python3 -m pip install -r /requirements.txt
+
+# Assuming installing to /usr/local
+ENV LD_LIBRARY_PATH=/usr/local/lib
+
+# Assuming installing to /usr/local
+ENV LD_LIBRARY_PATH=/usr/local/lib
+
+# extra interactive utilities and compilation_database generation
+RUN apt-get update \
+ && apt-get -qq install -y --no-install-recommends \
+ bear \
+ fd-find \
+ gdb \
+ less \
+ ripgrep
+
+# Add the group and user that match our ids
+RUN groupadd -g ${USER_GID} ${USERNAME} && \
+ adduser --disabled-password --uid ${USER_UID} --gid ${USER_GID} --gecos "" ${USERNAME} && \
+ echo "${USERNAME} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
+USER $USERNAME
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 000000000000..f3a64d03f367
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,39 @@
+{
+ "name": "Flux Core Python 3.6",
+ "dockerFile": "Dockerfile",
+ "context": "../",
+
+ "customizations": {
+ "vscode": {
+ "settings": {
+ "terminal.integrated.defaultProfile.linux": "bash",
+
+ // Ensure that Python autocomplete works out of the box
+ "python.autoComplete.extraPaths": [
+ "/usr/local/lib/flux/python3.8",
+ "/usr/local/lib/python3.8/site-packages",
+ "/workspaces/flux-core/src/bindings/python"
+ ],
+ "python.analysis.extraPaths": [
+ "/usr/local/lib/flux/python3.8",
+ "/usr/local/lib/python3.8/site-packages",
+ "/workspaces/flux-core/src/bindings/python"
+ ]
+ },
+ // Note to Flux Developers! We can add extensions here that you like
+ "extensions": [
+ "ms-vscode.cpptools", // C and C++ support
+ "sumneko.lua", // Lua support
+ "ms-python.python", // Python support
+ "GitHub.vscode-pull-request-github", // manage and review PRs
+ ]
+ }
+ },
+ "features": {
+ "ghcr.io/devcontainers/features/github-cli:1": {
+ "version": "latest"
+ }
+ },
+ // Needed for git security feature (this assumes you locally cloned to flux-core)
+ "postStartCommand": "git config --global --add safe.directory /workspaces/flux-core"
+}
diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
new file mode 100644
index 000000000000..51805017aab0
--- /dev/null
+++ b/.github/codeql/codeql-config.yml
@@ -0,0 +1,9 @@
+Name: "flux codeql defaults"
+queries:
+ - uses: security-and-quality
+paths:
+ - src
+paths-ignore:
+ - "**/flux/utils/**/*.py"
+ - "src/**/parsedatetime/**/*.py"
+ - "**/_flux/**/*.py"
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 000000000000..62020476bbf5
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,59 @@
+# Number of days of inactivity before an Issue or Pull Request becomes stale
+daysUntilStale: 365
+daysUntilClose: 14
+
+# Only these labels will be considered stale. Set to `[]` to disable:
+onlyLabels: []
+
+# Issues or Pull Requests with these labels will never be considered
+# stale. Set to `[]` to disable
+#
+exemptLabels:
+ - pinned
+ - security
+ - design
+ - confirmed
+
+# Set to true to ignore issues in a project (defaults to false)
+exemptProjects: true
+
+# Set to true to ignore issues in a milestone (defaults to false)
+exemptMilestones: true
+
+# Set to true to ignore issues with an assignee (defaults to false)
+exemptAssignees: false
+
+# Label to use when marking as stale
+staleLabel: wontfix
+
+# Comment to post when marking as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ activity for 365 days. It will be closed if no further activity occurs
+ within 14 days. Thank you for your contributions.
+
+# Comment to post when removing the stale label.
+# unmarkComment: >
+# Your comment here.
+
+# Comment to post when closing a stale Issue or Pull Request.
+# closeComment: >
+# Your comment here.
+
+# Limit the number of actions per hour, from 1-30. Default is 30
+limitPerRun: 20
+
+# Limit to only `issues` or `pulls`
+# only: issues
+
+# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
+# pulls:
+# daysUntilStale: 30
+# markComment: >
+# This pull request has been automatically marked as stale because it has not had
+# recent activity. It will be closed if no further activity occurs. Thank you
+# for your contributions.
+
+# issues:
+# exemptLabels:
+# - confirmed
diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml
new file mode 100644
index 000000000000..b5274cf65023
--- /dev/null
+++ b/.github/workflows/asan.yml
@@ -0,0 +1,32 @@
+on: [push, pull_request]
+name: asan
+jobs:
+ check-asan:
+ name: address-sanitizer check
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+ - run: git fetch --tags || true
+ - name: disable ASLR
+ run: |
+ sudo sysctl -w kernel.randomize_va_space=0
+ - name: docker-run-checks with ASan
+ timeout-minutes: 40
+ env:
+ PRELOAD: /usr/lib64/libasan.so.8
+ ASAN_OPTIONS: detect_leaks=0,start_deactivated=true,replace_str=true,verify_asan_link_order=false
+ FLUX_TEST_TIMEOUT: 300
+ TAP_DRIVER_QUIET: t
+ run: >
+ src/test/docker/docker-run-checks.sh \
+ --image=fedora36 --unit-test-only -j4 \
+ -- --with-flux-security --enable-sanitizer=address
+
+ - name: after failure
+ if: failure() || cancelled()
+ run: src/test/checks-annotate.sh
+
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 000000000000..7799db67b1c7
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,88 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ "master" ]
+ schedule:
+ - cron: '42 0 * * 0'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'cpp', 'python' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ queries: security-and-quality
+ config-file: ./.github/codeql/codeql-config.yml
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+
+ # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
+ - name: Install ubuntu dependencies
+ run: |
+ sudo apt update
+ sudo scripts/install-deps-deb.sh
+ - name: Install python dependencies
+ run: |
+ python3 -m pip install --upgrade pip
+ python3 -m pip install -r scripts/requirements-dev.txt
+ # Set the `CODEQL-PYTHON` environment variable to the Python executable
+ # that includes the dependencies
+ echo "CODEQL_PYTHON=$(which python3)" >> $GITHUB_ENV
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ # - name: Autobuild
+ # uses: github/codeql-action/autobuild@v2
+
+ # âšī¸ Command-line programs to run using the OS shell.
+ # đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+
+ # If the Autobuild fails above, remove it and uncomment the following three lines.
+ # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
+
+ - run: |
+ export FLUX_VERSION=0.0.0
+ ./autogen.sh
+ ./configure
+ make -j 4
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 16b30d20513f..125843d3c4fd 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,30 +1,277 @@
-on: pull_request
+on: [pull_request, push, merge_group]
+name: ci
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
jobs:
check-pr:
name: validate commits
runs-on: ubuntu-latest
+ if: github.event_name == 'pull_request'
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- run: git fetch origin master
- uses: flux-framework/pr-validator@master
+ spelling:
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v4
+ - name: Check Spelling
+ uses: crate-ci/typos@bcafd462cb07ef7ba57e34abf458fe20767e808b # v1.19.0
+
+ python-lint:
+ name: python linting
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/setup-python@v5
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+ - name: install linting and formatting deps
+ run: pip install -r scripts/requirements-dev.txt
+ - name: format and linting checks
+ run: pre-commit run --all-files
+
check-sched:
+ needs: [python-lint]
name: flux-sched check
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- - run: git fetch --tags
+ - run: git fetch --tags || true
- run: >
- src/test/docker/docker-run-checks.sh --install-only
- --tag=fluxrm/flux-core:bionic
+ src/test/docker/docker-run-checks.sh --install-only \
+ --tag=fluxrm/flux-core:bookworm
- run: >
- cd .. &&
- git clone https://github.com/flux-framework/flux-sched &&
+ cd .. && git clone https://github.com/flux-framework/flux-sched &&
cd flux-sched &&
- src/test/docker/docker-run-checks.sh -j 4 -i bionic
+ src/test/docker/docker-run-checks.sh -j 4 -i bookworm -- CXXFLAGS=-Wno-error=maybe-uninitialized
+
+ check-accounting:
+ needs: [python-lint]
+ name: flux-accounting check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+ - run: >
+ src/test/docker/docker-run-checks.sh --image=el8 --install-only \
+ --tag=fluxrm/flux-core:el8
+ - run: >
+ cd .. && git clone https://github.com/flux-framework/flux-accounting &&
+ cd flux-accounting && src/test/docker/docker-run-checks.sh -j 4
+
+ check-pmix:
+ needs: [python-lint]
+ name: flux-pmix check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+ - run: >
+ src/test/docker/docker-run-checks.sh
+ --image=el8
+ --install-only
+ --tag=fluxrm/flux-core:el8
+ - run: >
+ cd .. &&
+ git clone https://github.com/flux-framework/flux-pmix &&
+ cd flux-pmix &&
+ src/test/docker/docker-run-checks.sh -j 4 -i el8
+ --build-arg OMPI_BRANCH=v5.0.0rc12
+ --build-arg OPENPMIX_BRANCH=v4.2.3
+
+ check-pam:
+ needs: [python-lint]
+ name: flux-pam check
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+ - run: >
+ src/test/docker/docker-run-checks.sh
+ --image=el8
+ --install-only
+ --tag=fluxrm/flux-core:el8
+ - run: >
+ cd .. &&
+ git clone https://github.com/flux-framework/flux-pam &&
+ cd flux-pam &&
+ src/test/docker/docker-run-checks.sh -j 4 -i el8
+
+ build-macos:
+ needs: [python-lint]
+ name: macos build only
+ runs-on: macos-14
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+ - name: Install dependencies
+ run: scripts/install-deps-macos.sh
+ - name: autogen, configure
+ run: scripts/configure-macos.sh
+ - name: make, including test programs
+ run: make check -j4 TESTS=
+
+ generate-matrix:
+ # https://stackoverflow.com/questions/59977364
+ name: Generate build matrix
+ runs-on: ubuntu-latest
+ outputs:
+ matrix: ${{ steps.set-matrix.outputs.matrix }}
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+ - id: set-matrix
+ run: echo "matrix=$(src/test/generate-matrix.py)" >> $GITHUB_OUTPUT
+ - run: src/test/generate-matrix.py | jq -S .
+ - run: echo "GITHUB_BRANCH=${GITHUB_REF#refs/heads}" >> $GITHUB_OUTPUT
+ - run: echo "GITHUB_TAG=${GITHUB_REF#refs/tags}" >> $GITHUB_OUTPUT
+ - run: echo "EVENT_NAME=${{ github.event_name }}" >> $GITHUB_OUTPUT
+
+ ci-checks:
+ needs: [generate-matrix]
+ runs-on: ubuntu-latest
+ env:
+ TAP_DRIVER_QUIET: 1
+ FLUX_TEST_TIMEOUT: 300
+ DOCKER_REPO: fluxrm/flux-core
+ DOCKER_USERNAME: travisflux
+ DOCKER_PASSWORD: ${{ secrets.DOCKER_HUB_TRAVISFLUX_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ strategy:
+ matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
+ fail-fast: false
+ name: ${{matrix.name}}
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+
+ - name: fetch annotated tag
+ if: >
+ (matrix.create_release || matrix.docker_tag) &&
+ github.ref != 'refs/heads/master'
+ run: |
+ # Ensure git-describe works on a tag.
+ # (checkout@v4 action may have left current tag as
+ # lightweight instead of annotated. See
+ # https://github.com/actions/checkout/issues/290)
+ #
+ echo github.ref == ${{ github.ref }} ;
+ git fetch -f origin ${{ github.ref }}:${{ github.ref }} ;
+ echo git describe now reports $(git describe --always)
+
+ - name: coverage setup
+ env: ${{matrix.env}}
+ if: matrix.coverage
+ run: |
+ # Use python3 coverage to match version in flux docker image
+ sudo apt update ; \
+ sudo apt install -yy python3-pip ; \
+ pip3 install --upgrade pip ;
+ pip3 install --upgrade --force-reinstall coverage ;
+
+ - name: s3 setup
+ env: ${{matrix.env}}
+ if: matrix.test_s3
+ run: |
+ docker run -d -p 9000:9000 minio/minio server /data; \
+
+ - name: generate dumpfile from most recent flux-core tag
+ if: (matrix.create_release != true)
+ run: |
+ src/test/create-kvs-dumpfile.sh -d /tmp/dumpfile &&
+ if test -f /tmp/dumpfile/*.bz2; then
+ cp /tmp/dumpfile/*.tar.bz2 $(pwd)/t/job-manager/dumps/valid
+ fi
+
+ - name: docker buildx
+ uses: docker/setup-buildx-action@v3
+ if: matrix.needs_buildx
+
+ - name: setup qemu-user-static
+ run: |
+ docker run --rm --privileged aptman/qus -s -- -p --credential aarch64
+
+ - name: docker-run-checks
+ timeout-minutes: ${{matrix.timeout_minutes}}
+ env: ${{matrix.env}}
+ run: ${{matrix.command}}
+
+ - name: annotate errors
+ if: failure() || cancelled()
+ env: ${{matrix.env}}
+ run: src/test/checks-annotate.sh
+
+ - name: coverage report
+ if: success() && matrix.coverage
+ env:
+ DOCKER_REPO:
+ uses: codecov/codecov-action@v4
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ flags: ${{matrix.coverage_flags}}
+
+ - name: docker deploy
+ if: success() && matrix.docker_tag
+ env: ${{matrix.env}}
+ run: src/test/docker-deploy.sh
+
+ - name: create release
+ id: create_release
+ if: |
+ success()
+ && matrix.create_release
+ && github.repository == 'flux-framework/flux-core'
+ env: ${{matrix.env}}
+ uses: softprops/action-gh-release@v1
+ with:
+ tag_name: ${{ matrix.tag }}
+ name: flux-core ${{ matrix.tag }}
+ prerelease: true
+ files: flux-core*.tar.gz
+ body: |
+ View [Release Notes](https://github.com/${{ github.repository }}/blob/${{ matrix.tag }}/NEWS.md) for flux-core ${{ matrix.tag }}
+
+ generate-manifest:
+ name: Generate docker manifest
+ runs-on: ubuntu-latest
+ needs: [ci-checks]
+ env:
+ DOCKER_REPO: fluxrm/flux-core
+ DOCKER_USERNAME: travisflux
+ DOCKER_PASSWORD: ${{ secrets.DOCKER_HUB_TRAVISFLUX_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ steps:
+ - name: make and push manifest as fluxrm/flux-core
+ if: >
+ (startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master')
+ run: |
+ echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
+ docker manifest create fluxrm/flux-core:bookworm fluxrm/flux-core:bookworm-amd64 fluxrm/flux-core:bookworm-386 fluxrm/flux-core:bookworm-arm64
+ docker manifest push fluxrm/flux-core:bookworm
+ for d in el9 noble alpine ; do
+ docker manifest create fluxrm/flux-core:$d fluxrm/flux-core:$d-amd64 fluxrm/flux-core:$d-arm64
+ docker manifest push fluxrm/flux-core:$d
+ done
+
diff --git a/.gitignore b/.gitignore
index 8f7432c9db1a..92926972936d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@ libltdl/
# docs intermediate files
/doc/man*/*.xml
+/doc/_build
# Object files
*.o
@@ -86,6 +87,18 @@ Makefile
*.log
.dirstamp
+# ignore mypy generated cache directory
+.mypy_cache
+
+# ignore local, maybe generated tooling files
+compile_commands.json
+compile_flags.txt
+
+# local editor config dirs
+.idea
+.clangd
+.cache
+
# Rules to ignore auto-generated test harness scripts
test_*.t
!/src/bindings/python/test_commands/test_runner.t
diff --git a/.mergify.yml b/.mergify.yml
index 774fe44b9441..f54c993d0f57 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -1,18 +1,28 @@
+queue_rules:
+ - name: default
+ update_method: rebase
+ merge_method: merge
+
pull_request_rules:
- name: rebase and merge when passing all checks
conditions:
- base=master
- - status-success=continuous-integration/travis-ci/pr
- - status-success="validate commits"
- - status-success="flux-sched check"
- label="merge-when-passing"
- label!="work-in-progress"
+ - -title~=^\[*[Ww][Ii][Pp]
- "approved-reviews-by=@flux-framework/core"
- "#approved-reviews-by>0"
- "#changes-requested-reviews-by=0"
- - -title~=^\[*[Ww][Ii][Pp]
actions:
- merge:
- method: merge
- strict: smart
- strict_method: rebase
+ queue:
+ name: default
+ - name: remove outdated approved reviews
+ conditions:
+ - author!=@core
+ actions:
+ dismiss_reviews:
+ approved: true
+ changes_requested: false
+ message: |
+ Approving reviews have been dismissed because this pull request
+ was updated.
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 000000000000..1e16d5bcbb66
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,44 @@
+files: '^(src/bindings/python/flux|src/cmd|t/python/.*\.py|t/scripts/.*\.py)'
+exclude: "^(src/bindings/python/_flux/|src/bindings/python/flux/utils/|t/python/tap)"
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.0.1
+ hooks:
+ - id: check-added-large-files
+ - id: check-case-conflict
+ - id: check-shebang-scripts-are-executable
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
+ - id: mixed-line-ending
+
+ - repo: local
+ hooks:
+ - id: black
+ name: black
+ language: python
+ types: [python]
+ entry: black
+
+ - id: isort
+ name: isort
+ args: [--filter-files]
+ language: python
+ types: [python]
+ entry: isort
+
+ - id: flake8
+ name: flake8
+ language: python
+ types: [python]
+ entry: flake8
+
+ - id: mypy
+ name: mypy
+ language: python
+ types: [python]
+ entry: ./scripts/run_mypy.sh
+ - repo: https://github.com/netromdk/vermin
+ rev: v1.5.1
+ hooks:
+ - id: vermin
+ args: ['-t=3.6-', '--violations']
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 000000000000..3803a410de62
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,22 @@
+# .readthedocs.yaml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the version of Python and other tools you might need
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.11"
+
+# Build documentation in the docs/ directory with Sphinx
+sphinx:
+ configuration: doc/conf.py
+
+# We recommend specifying your dependencies to enable reproducible builds:
+# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
+python:
+ install:
+ - requirements: doc/requirements.txt
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index ff4e89b0c7fa..000000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,195 +0,0 @@
-sudo: required
-services: docker
-dist: trusty
-language: c
-
-jobs:
- include:
- - stage: 'style checks'
- name: 'python format'
- language: 'python'
- python: '3.6'
- install: pip install --upgrade black
- script: ./scripts/check-format
- before_deploy: skip
- deploy: skip
- after_success: skip
- after_failure: skip
- - stage: 'style checks'
- name: 'python lint'
- language: 'python'
- python: '3.6'
- install: pip install 'pylint==2.2.2' --force-reinstall
- script: pylint --rcfile=src/bindings/python/.pylintrc src/bindings/python/flux
- before_deploy: skip
- deploy: skip
- after_success: skip
- after_failure: skip
- - name: "Ubuntu: no configure flags"
- stage: test
- compiler: gcc
- env:
- - PYTHON_VERSION=2.7
- - name: "Ubuntu: py3.6 distcheck"
- stage: test
- compiler: gcc
- env:
- - DISTCHECK=t
- - PYTHON_VERSION=3.6
- - GITHUB_RELEASES_DEPLOY=t
- - name: "Ubuntu: gcc-8 address-sanitizer --with-flux-security"
- stage: test
- compiler: gcc-8
- env:
- - CC=gcc-8
- - CXX=g++-8
- - ARGS="--with-flux-security --enable-sanitizer=address"
- - PRELOAD=/usr/lib/gcc/x86_64-linux-gnu/8/libasan.so
- - ASAN_OPTIONS=detect_leaks=0 # TODO: fix/suppress tests so we can turn this on
- - PYTHON_VERSION=3.6
- - name: "Ubuntu: gcc-8 --with-flux-security/caliper, distcheck"
- stage: test
- compiler: gcc-8
- env:
- - CC=gcc-8
- - CXX=g++-8
- - ARGS="--with-flux-security --enable-caliper"
- - DISTCHECK=t
- - PYTHON_VERSION=2.7
- - name: "Ubuntu: clang-6.0 chain-lint --with-flux-security"
- stage: test
- compiler: clang-6.0
- env:
- - CC=clang-6.0
- - CXX=clang++-6.0
- - chain_lint=t
- - ARGS="--with-flux-security"
- - PYTHON_VERSION=2.7
- - name: "Ubuntu: COVERAGE=t, --with-flux-security --enable-caliper"
- stage: test
- compiler: gcc
- env:
- - COVERAGE=t
- - ARGS="--with-flux-security --enable-caliper"
- - PYTHON_VERSION=2.7
- - name: "Ubuntu: TEST_INSTALL docker-deploy"
- stage: test
- compiler: gcc
- env:
- - ARGS="--with-flux-security --enable-caliper"
- - TEST_INSTALL=t
- - DOCKER_TAG=t
- - PYTHON_VERSION=2.7
- - name: "Centos 7: security,caliper,docker-deploy"
- stage: test
- compiler: gcc
- env:
- - ARGS="--with-flux-security --enable-caliper --prefix=/usr"
- - IMG=centos7
- - DOCKER_TAG=t
- - PYTHON_VERSION=2.7
- - name: "Centos 8: py3.6,security,caliper,docker-deploy"
- stage: test
- compiler: gcc
- env:
- - ARGS="--with-flux-security --enable-caliper --prefix=/usr"
- - IMG=centos8
- - DOCKER_TAG=t
- - PYTHON_VERSION=3.6
-
-stages:
- - 'style checks'
- - test
-
-env:
- global:
- - TAP_DRIVER_QUIET=1
- - DOCKERREPO=fluxrm/flux-core
- - DOCKER_USERNAME=travisflux
- - secure: "Uga2i1Yu0PvWMFzOYvM9yxnAMDTgY17ZqeFlIN8MV3uoTCy6y61GULrMkKuhuI1sUfyugpFWVKIJo5jwTpsfG84f3o9lUTRgLPpTA2Xls8A/rmurF/QacVv6hZ2Zs2LQVlrM8BkT36TpT2NfWW2D2238kovqz3l5gIZKMClMvyk="
-
-cache:
- directories:
- - $HOME/.ccache
-
-before_install:
- # work around persistent write error bug from make in travis
- # see https://github.com/travis-ci/travis-ci/issues/4704#issuecomment-348435959
- - python -c 'import os,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); fcntl.fcntl(sys.stdout, fcntl.F_SETFL, flags&~os.O_NONBLOCK);'
- # die if non-blocking is still enabled
- - python -c 'import os,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); exit(flags&os.O_NONBLOCK);'
- # coveralls-lcov required only for coveralls upload:
- - if test "$COVERAGE" = "t" ; then gem install coveralls-lcov; fi
- - if test -z "${IMG}"; then IMG="bionic"; fi
- #
- # Tag image if this build is on master or result of a tag:
- - |
- if test "$DOCKER_TAG" = "t" \
- -a "$TRAVIS_REPO_SLUG" = "flux-framework/flux-core" \
- -a "$TRAVIS_PULL_REQUEST" = "false" \
- -a \( "$TRAVIS_BRANCH" = "master" -o -n "$TRAVIS_TAG" \); then
- export TAGNAME="${DOCKERREPO}:${IMG}${TRAVIS_TAG:+-${TRAVIS_TAG}}"
- echo "Tagging new image $TAGNAME"
- fi
-
-script:
- # Unshallow repository so git describe works.
- # (The one inside docker-run-checks may fail if git version is too old)
- - git fetch --unshallow --tags
- - |
- src/test/docker/docker-run-checks.sh -j2 \
- --image=${IMG} \
- ${TAGNAME:+--tag=${TAGNAME}} \
- -- --enable-docs ${ARGS}
-
-after_success:
- - ccache -s
- # Upload coverage results for COVERAGE run
- - |
- if test "$COVERAGE" = "t"; \
- then coveralls-lcov flux*-coverage.info; \
- bash <(curl -s https://codecov.io/bash); \
- fi
- # Deploy resulting docker image to Docker Hub with appropriate tag
- - |
- if test -n "$TAGNAME"; then
- echo "$DOCKER_PASSWORD" | \
- docker login -u "$DOCKER_USERNAME" --password-stdin && \
- docker push ${TAGNAME}
- # If this is the bionic build, then also tag without image name:
- if echo "$TAGNAME" | grep -q "bionic"; then
- t="${DOCKERREPO}:${TRAVIS_TAG:-latest}"
- docker tag "$TAGNAME" ${t} && \
- docker push ${t}
- fi
- fi
-
-after_failure:
- - find . -name test-suite.log | xargs -i sh -c 'printf "===XXX {} XXX===";cat {}'
- - find . -name t[0-9]*.output | xargs -i sh -c 'printf "\033[31mFound {}\033[39m\n";cat {}'
- - find . -name *.broker.log | xargs -i sh -c 'printf "\033[31mFound {}\033[39m\n";cat {}'
- - find . -name *.asan.* | xargs -i sh -c 'printf "\033[31mFound {}\033[39m\n";cat {}'
- - src/test/backtrace-all.sh
- - grep -q 'configure. exit 1' config.log && cat config.log
-
-before_deploy:
- # Get anchor (formatted properly) and base URI for latest tag in NEWS file
- - export ANCHOR=$(sed -n '/^flux-core version/{s/\.//g; s/\s/-/gp;Q}' NEWS.md)
- - export TAG_URI="https://github.com/${TRAVIS_REPO_SLUG}/blob/${TRAVIS_TAG}"
- - export TARBALL=$(echo flux-core*.tar.gz)
- - ls -l $TARBALL
- - echo "Deploying tag ${TRAVIS_TAG} as $TARBALL"
-
-deploy:
- provider: releases
- skip_cleanup: true
- file: $TARBALL
- prerelease: true
- body: "View [Release Notes](${TAG_URI}/NEWS.md#${ANCHOR}) for flux-core ${TRAVIS_TAG}"
- api_key:
- secure: I7ckZ7Ei9oLIe8WZ8OH3EgZz81IFCIekx+v/+g3sJa6q15URlfZhVVFtiUpsJRktHcb39AflWZiEIX+HdUZyXtuTt9IES1XBIKH7x/zUL0x6f1DZKAhBx9ktYzdO/M+SpmDUg6RYxcdjVmSHZ9u935TDo104U+dY0990ZSFrpco=
- on:
- # Only deploy from travis builder with GITHUB_RELEASES_DEPLOY set
- condition: $GITHUB_RELEASES_DEPLOY = "t"
- tags: true
- repo: flux-framework/flux-core
diff --git a/.typos.toml b/.typos.toml
new file mode 100644
index 000000000000..f177081a81fe
--- /dev/null
+++ b/.typos.toml
@@ -0,0 +1,37 @@
+# do not check code copied into the project
+# do not check sha code, lots of hashing false positives
+# do not check testing data
+[files]
+extend-exclude = [
+ "config/*",
+ "src/common/libev/*",
+ "src/common/libccan/*",
+ "src/common/liblsd/*",
+ "src/common/libtomlc99/*",
+ "src/common/libczmqcontainers/*",
+ "src/bindings/python/flux/utils/parsedatetime/*",
+ "t/sharness.sh",
+ "src/common/libutil/sha1.c",
+ "src/common/libutil/test/sha1.c",
+ "src/common/libutil/test/blobref.c",
+ "src/common/libmissing/*.[ch]",
+ "t/hwloc-data/*",
+ "doc/test/spell.en.pws",
+ "t/resource/resource.eventlog.*",
+ "t/sharness",
+]
+
+[default.extend-words]
+# in hwloc output
+hsi = "hsi"
+# commonly used names/variables that aren't typos
+fo = "fo"
+ba = "ba"
+inout = "inout"
+trun = "trun"
+fullset = "fullset"
+mone = "mone"
+requestor = "requestor"
+requestors = "requestors"
+clen = "clen"
+WRONLY = "WRONLY"
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 000000000000..eef35b49d3b2
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,29 @@
+{
+ "configurations": [
+ {
+ "name": "Linux arm64",
+ "includePath": [
+ "${workspaceFolder}/**"
+ ],
+ "defines": [],
+ "compilerPath": "/usr/bin/gcc",
+ "cStandard": "c99",
+ "cppStandard": "c++14",
+ "intelliSenseMode": "linux-gcc-arm64",
+ "compileCommands": "",
+ "mergeConfigurations": false
+ },
+ {
+ "name": "Linux amd64",
+ "includePath": [
+ "${workspaceFolder}/**"
+ ],
+ "defines": [],
+ "compilerPath": "/usr/bin/gcc",
+ "cStandard": "c99",
+ "cppStandard": "c++14",
+ "intelliSenseMode": "linux-gcc-x64",
+ }
+ ],
+ "version": 4
+}
\ No newline at end of file
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 000000000000..515b018832c3
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,8 @@
+{
+ "recommendations": [
+ "ms-vscode.cpptools",
+ "github.vscode-pull-request-github",
+ "sumneko.lua",
+ "ms-python.python"
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000000..eb2d64a75b77
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,34 @@
+{
+ "python.defaultInterpreterPath": "python3",
+ "python.autoComplete.extraPaths": [
+ "./build/src/bindings/python",
+ "./src/bindings/python",
+ "./t/python/tap",
+ ],
+ "python.analysis.extraPaths": [
+ "./build/src/bindings/python",
+ "./src/bindings/python",
+ "./t/python/tap",
+ ],
+ "Lua.runtime.path": [
+ "?.lua",
+ "?/init.lua",
+ "${workspaceFolder}/src/bindings/lua/?.lua",
+ "${workspaceFolder}/src/bindings/lua/?/init.lua"
+ ],
+ "files.associations": {
+ "**/lua/**/*.t": "lua",
+ "*.t": "shellscript"
+ },
+ "C_Cpp.autoAddFileAssociations": false,
+ "Lua.completion.autoRequire": true,
+ "Lua.diagnostics.globals": [
+ "shell",
+ "plugin",
+ "task"
+ ],
+ "python.formatting.provider": "black",
+ "python.linting.flake8Enabled": true,
+ "python.linting.enabled": true,
+ "python.linting.mypyEnabled": true,
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 000000000000..0508bf959cd7
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,54 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
+ // for the documentation about the tasks.json format
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "configure",
+ "type": "shell",
+ "command": "libtoolize --automake --copy && autoreconf --verbose --install && ./configure --prefix=$(pwd)/install",
+ "group": {
+ "kind": "build",
+ "isDefault": false
+ }
+ },
+ {
+ "label": "make",
+ "type": "shell",
+ "command": "env SHELL=/bin/sh make -j 8 all V=1",
+ "problemMatcher": [
+ "$gcc"
+ ],
+ "group": {
+ "kind": "build",
+ "isDefault": false
+ }
+ },
+ {
+ "label": "check",
+ "type": "shell",
+ "command": "env SHELL=/bin/sh make -j 8 check V=1 VERBOSE=1",
+ "problemMatcher": [
+ "$gcc",
+ {
+ "owner": "automake",
+ "fileLocation": [
+ "relative",
+ "${workspaceFolder}/t/"
+ ],
+ "pattern": [{
+ "kind": "file",
+ "regexp": "^([FE][^\\s:]*):\\s+([^\\s]+)\\s+(\\d+)\\s+(.*)$",
+ "severity": 1,
+ "file": 2,
+ "message": 4
+ }]
+ }
+ ],
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/AUTHORS b/AUTHORS
deleted file mode 100644
index aac4dcedd02c..000000000000
--- a/AUTHORS
+++ /dev/null
@@ -1,21 +0,0 @@
-Dong Ahn
-Jon Bringhurst
-Al Chu
-James Corbett
-Chris Dunlap
-Todd Gamblin
-Jim Garlick
-Mark Grondona
-Matthieu Hautreux
-Sam Heinz
-Stephen Herbein
-Don Lipari
-Andre Merzky
-Dan Milroy
-Chris Morrone
-Chris Moussa
-Tapasya Patki
-Suraj Prabhakaran
-Barry Rountree
-Tom Scogland
-Becky Springmeyer
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9310be85cf18..8fa92ab686f7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,6 +26,6 @@ in the following RFCs from the [flux-framework/rfc][1] project:
to Flux projects.
[1]: https://github.com/flux-framework/rfc
-[2]: https://github.com/flux-framework/rfc/blob/master/spec_1.adoc
-[3]: https://github.com/flux-framework/rfc/blob/master/spec_2.adoc
-[4]: https://github.com/flux-framework/rfc/blob/master/spec_7.adoc
+[2]: https://flux-framework.rtfd.io/projects/flux-rfc/en/latest/spec_1.html
+[3]: https://flux-framework.rtfd.io/projects/flux-rfc/en/latest/spec_2.html
+[4]: https://flux-framework.rtfd.io/projects/flux-rfc/en/latest/spec_7.html
diff --git a/COPYING b/COPYING
deleted file mode 100644
index 0a041280bd00..000000000000
--- a/COPYING
+++ /dev/null
@@ -1,165 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
- This version of the GNU Lesser General Public License incorporates
-the terms and conditions of version 3 of the GNU General Public
-License, supplemented by the additional permissions listed below.
-
- 0. Additional Definitions.
-
- As used herein, "this License" refers to version 3 of the GNU Lesser
-General Public License, and the "GNU GPL" refers to version 3 of the GNU
-General Public License.
-
- "The Library" refers to a covered work governed by this License,
-other than an Application or a Combined Work as defined below.
-
- An "Application" is any work that makes use of an interface provided
-by the Library, but which is not otherwise based on the Library.
-Defining a subclass of a class defined by the Library is deemed a mode
-of using an interface provided by the Library.
-
- A "Combined Work" is a work produced by combining or linking an
-Application with the Library. The particular version of the Library
-with which the Combined Work was made is also called the "Linked
-Version".
-
- The "Minimal Corresponding Source" for a Combined Work means the
-Corresponding Source for the Combined Work, excluding any source code
-for portions of the Combined Work that, considered in isolation, are
-based on the Application, and not on the Linked Version.
-
- The "Corresponding Application Code" for a Combined Work means the
-object code and/or source code for the Application, including any data
-and utility programs needed for reproducing the Combined Work from the
-Application, but excluding the System Libraries of the Combined Work.
-
- 1. Exception to Section 3 of the GNU GPL.
-
- You may convey a covered work under sections 3 and 4 of this License
-without being bound by section 3 of the GNU GPL.
-
- 2. Conveying Modified Versions.
-
- If you modify a copy of the Library, and, in your modifications, a
-facility refers to a function or data to be supplied by an Application
-that uses the facility (other than as an argument passed when the
-facility is invoked), then you may convey a copy of the modified
-version:
-
- a) under this License, provided that you make a good faith effort to
- ensure that, in the event an Application does not supply the
- function or data, the facility still operates, and performs
- whatever part of its purpose remains meaningful, or
-
- b) under the GNU GPL, with none of the additional permissions of
- this License applicable to that copy.
-
- 3. Object Code Incorporating Material from Library Header Files.
-
- The object code form of an Application may incorporate material from
-a header file that is part of the Library. You may convey such object
-code under terms of your choice, provided that, if the incorporated
-material is not limited to numerical parameters, data structure
-layouts and accessors, or small macros, inline functions and templates
-(ten or fewer lines in length), you do both of the following:
-
- a) Give prominent notice with each copy of the object code that the
- Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the object code with a copy of the GNU GPL and this license
- document.
-
- 4. Combined Works.
-
- You may convey a Combined Work under terms of your choice that,
-taken together, effectively do not restrict modification of the
-portions of the Library contained in the Combined Work and reverse
-engineering for debugging such modifications, if you also do each of
-the following:
-
- a) Give prominent notice with each copy of the Combined Work that
- the Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the Combined Work with a copy of the GNU GPL and this license
- document.
-
- c) For a Combined Work that displays copyright notices during
- execution, include the copyright notice for the Library among
- these notices, as well as a reference directing the user to the
- copies of the GNU GPL and this license document.
-
- d) Do one of the following:
-
- 0) Convey the Minimal Corresponding Source under the terms of this
- License, and the Corresponding Application Code in a form
- suitable for, and under terms that permit, the user to
- recombine or relink the Application with a modified version of
- the Linked Version to produce a modified Combined Work, in the
- manner specified by section 6 of the GNU GPL for conveying
- Corresponding Source.
-
- 1) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (a) uses at run time
- a copy of the Library already present on the user's computer
- system, and (b) will operate properly with a modified version
- of the Library that is interface-compatible with the Linked
- Version.
-
- e) Provide Installation Information, but only if you would otherwise
- be required to provide such information under section 6 of the
- GNU GPL, and only to the extent that such information is
- necessary to install and execute a modified version of the
- Combined Work produced by recombining or relinking the
- Application with a modified version of the Linked Version. (If
- you use option 4d0, the Installation Information must accompany
- the Minimal Corresponding Source and Corresponding Application
- Code. If you use option 4d1, you must provide the Installation
- Information in the manner specified by section 6 of the GNU GPL
- for conveying Corresponding Source.)
-
- 5. Combined Libraries.
-
- You may place library facilities that are a work based on the
-Library side by side in a single library together with other library
-facilities that are not Applications and are not covered by this
-License, and convey such a combined library under terms of your
-choice, if you do both of the following:
-
- a) Accompany the combined library with a copy of the same work based
- on the Library, uncombined with any other library facilities,
- conveyed under the terms of this License.
-
- b) Give prominent notice with the combined library that part of it
- is a work based on the Library, and explaining where to find the
- accompanying uncombined form of the same work.
-
- 6. Revised Versions of the GNU Lesser General Public License.
-
- The Free Software Foundation may publish revised and/or new versions
-of the GNU Lesser General Public License from time to time. Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Library as you received it specifies that a certain numbered version
-of the GNU Lesser General Public License "or any later version"
-applies to it, you have the option of following the terms and
-conditions either of that published version or of any later version
-published by the Free Software Foundation. If the Library as you
-received it does not specify a version number of the GNU Lesser
-General Public License, you may choose any version of the GNU Lesser
-General Public License ever published by the Free Software Foundation.
-
- If the Library as you received it specifies that a proxy can decide
-whether future versions of the GNU Lesser General Public License shall
-apply, that proxy's public statement of acceptance of any version is
-permanent authorization for you to choose that version for the
-Library.
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index 7d1c323beae7..000000000000
--- a/INSTALL
+++ /dev/null
@@ -1,365 +0,0 @@
-Installation Instructions
-*************************
-
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
-2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
- Copying and distribution of this file, with or without modification,
-are permitted in any medium without royalty provided the copyright
-notice and this notice are preserved. This file is offered as-is,
-without warranty of any kind.
-
-Basic Installation
-==================
-
- Briefly, the shell commands `./configure; make; make install' should
-configure, build, and install this package. The following
-more-detailed instructions are generic; see the `README' file for
-instructions specific to this package. Some packages provide this
-`INSTALL' file but do not implement all of the features documented
-below. The lack of an optional feature in a given package is not
-necessarily a bug. More recommendations for GNU packages can be found
-in *note Makefile Conventions: (standards)Makefile Conventions.
-
- The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation. It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
- It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring. Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.
-
- If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
- The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'. You need `configure.ac' if
-you want to change it or regenerate `configure' using a newer version
-of `autoconf'.
-
- The simplest way to compile this package is:
-
- 1. `cd' to the directory containing the package's source code and type
- `./configure' to configure the package for your system.
-
- Running `configure' might take a while. While running, it prints
- some messages telling which features it is checking for.
-
- 2. Type `make' to compile the package.
-
- 3. Optionally, type `make check' to run any self-tests that come with
- the package, generally using the just-built uninstalled binaries.
-
- 4. Type `make install' to install the programs and any data files and
- documentation. When installing into a prefix owned by root, it is
- recommended that the package be configured and built as a regular
- user, and only the `make install' phase executed with root
- privileges.
-
- 5. Optionally, type `make installcheck' to repeat any self-tests, but
- this time using the binaries in their final installed location.
- This target does not install anything. Running this target as a
- regular user, particularly if the prior `make install' required
- root privileges, verifies that the installation completed
- correctly.
-
- 6. You can remove the program binaries and object files from the
- source code directory by typing `make clean'. To also remove the
- files that `configure' created (so you can compile the package for
- a different kind of computer), type `make distclean'. There is
- also a `make maintainer-clean' target, but that is intended mainly
- for the package's developers. If you use it, you may have to get
- all sorts of other programs in order to regenerate files that came
- with the distribution.
-
- 7. Often, you can also type `make uninstall' to remove the installed
- files again. In practice, not all packages have tested that
- uninstallation works correctly, even though it is required by the
- GNU Coding Standards.
-
- 8. Some packages, particularly those that use Automake, provide `make
- distcheck', which can by used by developers to test that all other
- targets like `make install' and `make uninstall' work correctly.
- This target is generally not run by end users.
-
-Compilers and Options
-=====================
-
- Some systems require unusual options for compilation or linking that
-the `configure' script does not know about. Run `./configure --help'
-for details on some of the pertinent environment variables.
-
- You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment. Here
-is an example:
-
- ./configure CC=c99 CFLAGS=-g LIBS=-lposix
-
- *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
- You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory. To do this, you can use GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'. This
-is known as a "VPATH" build.
-
- With a non-GNU `make', it is safer to compile the package for one
-architecture at a time in the source code directory. After you have
-installed the package for one architecture, use `make distclean' before
-reconfiguring for another architecture.
-
- On MacOS X 10.5 and later systems, you can create libraries and
-executables that work on multiple system types--known as "fat" or
-"universal" binaries--by specifying multiple `-arch' options to the
-compiler but only a single `-arch' option to the preprocessor. Like
-this:
-
- ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
- CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
- CPP="gcc -E" CXXCPP="g++ -E"
-
- This is not guaranteed to produce working output in all cases, you
-may have to build one architecture at a time and combine the results
-using the `lipo' tool if you have problems.
-
-Installation Names
-==================
-
- By default, `make install' installs the package's commands under
-`/usr/local/bin', include files under `/usr/local/include', etc. You
-can specify an installation prefix other than `/usr/local' by giving
-`configure' the option `--prefix=PREFIX', where PREFIX must be an
-absolute file name.
-
- You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files. If you
-pass the option `--exec-prefix=PREFIX' to `configure', the package uses
-PREFIX as the prefix for installing programs and libraries.
-Documentation and other data files still use the regular prefix.
-
- In addition, if you use an unusual directory layout you can give
-options like `--bindir=DIR' to specify different values for particular
-kinds of files. Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them. In general, the
-default for these options is expressed in terms of `${prefix}', so that
-specifying just `--prefix' will affect all of the other directory
-specifications that were not explicitly provided.
-
- The most portable way to affect installation locations is to pass the
-correct locations to `configure'; however, many packages provide one or
-both of the following shortcuts of passing variable assignments to the
-`make install' command line to change installation locations without
-having to reconfigure or recompile.
-
- The first method involves providing an override variable for each
-affected directory. For example, `make install
-prefix=/alternate/directory' will choose an alternate location for all
-directory configuration variables that were expressed in terms of
-`${prefix}'. Any directories that were specified during `configure',
-but not in terms of `${prefix}', must each be overridden at install
-time for the entire installation to be relocated. The approach of
-makefile variable overrides for each directory variable is required by
-the GNU Coding Standards, and ideally causes no recompilation.
-However, some platforms have known limitations with the semantics of
-shared libraries that end up requiring recompilation when using this
-method, particularly noticeable in packages that use GNU Libtool.
-
- The second method involves providing the `DESTDIR' variable. For
-example, `make install DESTDIR=/alternate/directory' will prepend
-`/alternate/directory' before all installation names. The approach of
-`DESTDIR' overrides is not required by the GNU Coding Standards, and
-does not work on platforms that have drive letters. On the other hand,
-it does better at avoiding recompilation issues, and works well even
-when some directory options were not specified in terms of `${prefix}'
-at `configure' time.
-
-Optional Features
-=================
-
- If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
- Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System). The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
- For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
- Some packages offer the ability to configure how verbose the
-execution of `make' will be. For these packages, running `./configure
---enable-silent-rules' sets the default to minimal output, which can be
-overridden with `make V=1'; while running `./configure
---disable-silent-rules' sets the default to verbose, which can be
-overridden with `make V=0'.
-
-Particular systems
-==================
-
- On HP-UX, the default C compiler is not ANSI C compatible. If GNU
-CC is not installed, it is recommended to use the following options in
-order to use an ANSI C compiler:
-
- ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
-
-and if that doesn't work, install pre-built binaries of GCC for HP-UX.
-
- On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
-parse its `' header file. The option `-nodtk' can be used as
-a workaround. If GNU CC is not installed, it is therefore recommended
-to try
-
- ./configure CC="cc"
-
-and if that doesn't work, try
-
- ./configure CC="cc -nodtk"
-
- On Solaris, don't put `/usr/ucb' early in your `PATH'. This
-directory contains several dysfunctional programs; working variants of
-these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
-in your `PATH', put it _after_ `/usr/bin'.
-
- On Haiku, software installed for all users goes in `/boot/common',
-not `/usr/local'. It is recommended to use the following options:
-
- ./configure --prefix=/boot/common
-
-Specifying the System Type
-==========================
-
- There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on. Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
- CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
- OS
- KERNEL-OS
-
- See the file `config.sub' for the possible values of each field. If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
- If you are _building_ compiler tools for cross-compiling, you should
-use the option `--target=TYPE' to select the type of system they will
-produce code for.
-
- If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
- If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists. Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
- Variables not defined in a site shell script can be set in the
-environment passed to `configure'. However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost. In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'. For example:
-
- ./configure CC=/usr/local2/bin/gcc
-
-causes the specified `gcc' to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-Unfortunately, this technique does not work for `CONFIG_SHELL' due to
-an Autoconf bug. Until the bug is fixed you can use this workaround:
-
- CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
-
-`configure' Invocation
-======================
-
- `configure' recognizes the following options to control how it
-operates.
-
-`--help'
-`-h'
- Print a summary of all of the options to `configure', and exit.
-
-`--help=short'
-`--help=recursive'
- Print a summary of the options unique to this package's
- `configure', and exit. The `short' variant lists options used
- only in the top level, while the `recursive' variant lists options
- also present in any nested packages.
-
-`--version'
-`-V'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`--cache-file=FILE'
- Enable the cache: use and save the results of the tests in FILE,
- traditionally `config.cache'. FILE defaults to `/dev/null' to
- disable caching.
-
-`--config-cache'
-`-C'
- Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
- Do not print messages saying which checks are being made. To
- suppress all normal output, redirect it to `/dev/null' (any error
- messages will still be shown).
-
-`--srcdir=DIR'
- Look for the package's source code in directory DIR. Usually
- `configure' can determine that directory automatically.
-
-`--prefix=DIR'
- Use DIR as the installation prefix. *note Installation Names::
- for more details, including other options available for fine-tuning
- the installation locations.
-
-`--no-create'
-`-n'
- Run the configure checks, but stop before creating any output
- files.
-
-`configure' also accepts some other, not widely useful, options. Run
-`configure --help' for more details.
-
diff --git a/LICENSE b/LICENSE
deleted file mode 120000
index d24842f3cdcf..000000000000
--- a/LICENSE
+++ /dev/null
@@ -1 +0,0 @@
-COPYING
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000000..0a041280bd00
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/Makefile.am b/Makefile.am
index 0233470630a6..361e819f8e7d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,15 @@ EXTRA_DIST = \
config/tap-driver.sh \
config/tap-driver.py \
NOTICE.LLNS \
- README.md
+ LICENSE \
+ README.md \
+ vscode.md \
+ NEWS.md \
+ scripts/requirements-dev.txt \
+ scripts/install-deps-deb.sh \
+ scripts/install-deps-rpm.sh \
+ scripts/install-deps-macos.sh \
+ scripts/configure-macos.sh
ACLOCAL_AMFLAGS = -I config
@@ -23,11 +31,17 @@ CODE_COVERAGE_IGNORE_PATTERN = \
"/usr/lib*" \
"*/bindings/python/*" \
"*/common/liblsd/*" \
- "*/common/libutil/sds.*" \
"*/common/liboptparse/getopt*" \
"*/common/libtestutil/*" \
- "*/common/libyuarel/*"
+ "*/common/libyuarel/*" \
+ "*/common/libczmqcontainers/*" \
+ "*/common/libccan/*" \
+ "*/common/libmissing/*"
+# ignore lcov errors to avoid merge mismatch issue since lcov < 2 doesn't offer
+# an option to just ignore this error, we use this env var to ignore all, see:
+# https://github.com/flux-framework/flux-core/issues/6078
+export GCOV_ERROR_FILE=/dev/null
CODE_COVERAGE_LCOV_OPTIONS =
@CODE_COVERAGE_RULES@
@@ -41,3 +55,15 @@ CODE_COVERAGE_LCOV_OPTIONS =
# file's SUBDIRS, ensures that "all" is built before any of the
# recursive checks.
check-local: all
+
+check-prep: all
+ cd src && $(MAKE) check
+ cd doc && $(MAKE) check
+ cd t && $(MAKE) check-prep
+
+export DEB_BUILD_OPTIONS ?= nocheck terse
+deb: debian scripts/debbuild.sh
+ +@$(top_srcdir)/scripts/debbuild.sh $(abs_top_srcdir)
+
+clean-local:
+ @rm -rf debbuild
diff --git a/NEWS b/NEWS
deleted file mode 100644
index 968af700b073..000000000000
--- a/NEWS
+++ /dev/null
@@ -1 +0,0 @@
-Full Release Notes for flux-core can be found in the NEWS.md file.
diff --git a/NEWS.md b/NEWS.md
index 7b43ae2095a1..f6e9c03cc364 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,2814 @@
+flux-core version 0.69.0 - 2024-12-03
+-------------------------------------
+
+## New Features
+ * add flux module stats `--rusage=[self|children|thread]` optional argument
+ (#6471)
+ * add `-S, --setattr` and `-c, --config-path` options directly to `flux
+ start` (#6452)
+ * job-ingest: improve cleanup and stats output (#6438)
+ * libflux: add `flux_watcher_is_active()` (#6436)
+ * indicate held jobs in the` INFO` column of `flux jobs` output (#6430)
+ * recursively update instead of replacing tables when loading Flux
+ configuration (#6424)
+ * convert ISO timestamp output from UTC to local time + offset in `flux
+ dmesg` and eventlog commands (#6423)
+ * support flux uri --wait JOBID (#6443)
+ * skip "empty" lines of output in `flux resource list` with `--skip-empty`
+ or `--include` (#6460)
+
+## Fixes
+ * libfileref: fix segfault for files >2G (#6462)
+ * fix macos portability issues (#6454, #6468)
+ * fix multiple issues in the `flux job attach` statusline (#6442)
+ * librlist: avoid unnecessary hwloc dependencies (#6450)
+ * python: call shutdown() on executor in job validator (#6435)
+ * increase default prolog kill-timeout from 10s to 1m (#6431)
+ * job-manager/history: optimize list insertion (#6422)
+
+## Cleanup
+ * kvs-watch: misc cleanup (#6458)
+ * build: misc cleanup (#6451)
+ * job-manager: clean up queue code (#6448)
+ * remove `flux-perilog-run` (#6447)
+
+## CI/Testsuite/Documentation
+ * doc: improve `--include` documentation in flux-resource(1) (#6459)
+ * doc: improve housekeeping documentation (#6425)
+ * doc: launch jobs with systemd in the admin guide (#6427)
+
+
+flux-core version 0.68.0 - 2024-11-06
+-------------------------------------
+
+This release requires flux-security >= 0.13.0 as the IMP signal handling
+strategy has changed per RFC 15.
+
+## New Features
+ * update multi-user signaling to track flux-security 0.13.0 IMP changes
+ (#6408)
+ * add cleanup timeout for systemctl stop flux on rank 0 (#6397)
+ * flux-exec: use subprocess credits to avoid overflowing stdin buffers
+ (#6370)
+ * libsubprocess: support flow control on writes via credits (#6353)
+ * python: usability improvements for `JournalConsumer` class (#6390)
+ * python: add `flux.job.JournalConsumer` class with a simplified interface
+ for job manager journal consumers (#6386)
+ * support `sort:` prefix for format strings and `--sort` option to `flux
+ jobs` (#6380)
+ * flux-housekeeping: add `-i, --include=TARGETS` option to `flux
+ housekeeping list` (#6382)
+ * show response result in message traces (#6359)
+ * libsubprocess: invert SETPGRP flag logic (#6082)
+ * add --full option to display payloads in message tracing programs (#6347)
+
+
+## Fixes
+ * libsubprocess: close extra file descriptors (#6416)
+ * resolve perilog plugin issue that lets a job start after prolog timeout
+ when cancellation fails (#6412)
+ * frobnicator: allow queue-specific defaults to override global defaults
+ (#6403)
+ * sdexec: set KillMode=process SendSIGKILL=no for multi-user jobs (#6402)
+ * broker: detect mismatched bootstrap.hosts configuration (#6393)
+ * libsubprocess: take reference on callbacks (#6384)
+ * python: cleanup, fixes, and unit tests for flux.util.OutputFormat (#6374)
+ * libsubprocess: misc fixes (#6379)
+ * sched-simple: improve unsupported resource type exception (#6372)
+ * libsubprocess: ensure bulk-exec output is terminated (#6368)
+ * libsubprocess: check bufsize is > 0 (#6365)
+ * kvs: fix whitespace issues (#6356)
+ * allow project to be built with NDEBUG (#6355)
+ * systemd: make scripts fail if systemctl start does (#6346)
+ * improve policy/queues config error messages (#6339)
+ * make flux resource drain -o long reason expandable (#6338)
+
+## Cleanup
+ * job-archive: remove module (#6378)
+
+## CI/Testsuite/Documentation
+ * broker/test: avoid race in zeromq cleanup (#6405)
+ * docker: add missing tag of flux-core el8 image (#6401)
+ * doc: add debugging notes (#6369)
+ * doc: update link to flux-accounting guide (#6373)
+ * flux-jobs(1): document unlimited --count value (#6364)
+ * testsuite: add --raw-response opt to rpc test program (#6342)
+ * testsuite: improve test_must_fail_or_be_killed function (#6343)
+ * docs: rfc flux-config-bootstrap diagram (#6411)
+
+
+flux-core version 0.67.0 - 2024-10-01
+-------------------------------------
+
+## New Features
+ * include hostnames in flux resource undrain error message (#6335)
+ * libsubprocess: increase output watcher priority (#6317)
+ * libflux: support modifying watcher priority via
+ `flux_watcher_set_priority()` (#6316)
+ * add `--force` option to `flux resource undrain` (#6312)
+ * autoconf: support python 3.12 (#6303)
+ * flux-bulksubmit: support `{}` in more options like `--cwd=`, `--signal=`,
+ `--taskmap=`, etc. (#6299)
+ * add flux-lptest (#6301)
+ * broker: use enclosing instance tbon.interface-hint unless overridden
+ (#6283)
+ * shell/oom: log more detail when tasks are killed (#6289)
+ * support expandable width output formats and use them in `flux resource
+ list` to avoid truncation of queue field (#6284)
+ * python: update Flux handle location in validator plugin API (#6282)
+ * broker: call `PMI_Abort()` if something goes wrong during PMI bootstrap
+ (#6279)
+ * add tbon.interface-hint broker attribute / configuration key with CIDR
+ network support (#6277)
+ * support configuration of require-instance and other job
+ validator/frobnicator plugins in broker config TOML (#6305)
+ * validator: allow configurable minimum job size in the require-instance
+ validator plugin (#6258)
+ * display nodes in housekeeping in `flux resource status` (#6263)
+ * shell: output stdio output size warning (#6274)
+ * python: add `conf_get()` convenience method to `flux.Flux` handle (#6267)
+ * limit output to 1G in single user instances (#6268)
+
+## Fixes
+ * systemd: improve housekeeping drain message (#6334)
+ * perilog: never send SIGKILL to prolog/epilog, drain active nodes after
+ kill-timeout instead (#6330)
+ * perilog: fix kill of prolog/epilog when using IMP (#6324)
+ * perilog: fix `FLUX_JOB_USERID` in epilog after canceled prolog (#6320)
+ * flux job info: improve error messages (#6331)
+ * libsubprocess: fix bulk-exec reporting of active ranks (#6326)
+ * libsubprocess: do not spin on large lines (#6281)
+ * configure: add check for valid version (#6276)
+ * etc: minor improvements for bash completions (#6332)
+ * perilog: ensure default prolog timeout matches documentation (#6270)
+ * hostlist: remove allocations in `hostrange_find` (#6259)
+
+## CI/Testsuite/Documentation
+ * libsubprocess: add extra documentation (#6307)
+ * format: fix clang-format file (#6280)
+ * doc: python: fix JobList default documentation (#6309)
+ * doc: add dash to flux-job(1) manpage (#6313)
+ * doc: add warning about Python argparse in flux-jobs(1) (#6285)
+ * doc: fix typo in `FLUX_IPADDR_INTERFACE` entry in `flux-environment(7)`
+ (#6271)
+ * doc: update admin guide for systemd perilog (#6261)
+ * doc: add warning about stdio paths in submission cli man pages (#6333)
+
+
+flux-core version 0.66.0 - 2024-09-03
+-------------------------------------
+
+## New Features
+ * support display of `allocated` nodes in `flux resource status` (#6253)
+ * support `resource.scheduling` in config TOML to amend configured R with
+ a scheduling key (#6252)
+ * perilog: support direct execution of prolog/epilog on job ranks for
+ better performance (#6235)
+ * flux-hostlist: change default source from `local` to `stdin` (#6246)
+ * support short option `-S` for `--setattr=` in job submission commands
+ (#6238)
+ * content-sqlite: set sqlite pragmas with flux-config (#6222)
+ * content-sqlite: add sqlite config to module stats (#6221)
+ * content: allow content.flush to return errors (#6175)
+ * flux-jobs: add `-i, --include=HOSTS|RANKS` option (#6209)
+ * add flux module trace (#6203, #6206)
+ * include offline nodes in flux overlay errors output (#6201)
+
+## Fixes
+ * run epilog even if job prolog is failed or is canceled (#6249)
+ * progress: ensure we don't access outside style (#6250)
+ * housekeeping: deprecate use-systemd-config option (#6241)
+ * Fix handling of `--` used to separate options from command in `flux
+ submit`, `run`, and `batch` (#6234)
+ * libsubprocess: minor improvements to bulk-exec (#6233)
+ * update feasibility RPCs to conform to RFC 27 (#6223)
+ * libev: fix memory fence on i386 under valgrind (#6224)
+ * job-manager: skip housekeeping for alloc-bypass jobs (#6219)
+ * cron: use `posix_spawn()` for cron tasks when possible (#6214)
+ * kvs: correct code logic about what is an append (#6210)
+ * avoid idset leak when nodes leave the broker.online group (#6198)
+ * kvs: correct transaction-merge option parsing (#6204)
+
+## Cleanup
+ * content-sqlite: misc cleanup (#6220)
+
+## CI/Testsuite/Documentation
+ * doc: add dependency example (#6226)
+ * mergify: use updated keys before deprecation bites (#6225)
+ * testsuite: fix racy flux job attach test (#6212)
+ * matrix: remove fedora40 arm again (#6200)
+
+
+flux-core version 0.65.0 - 2024-08-06
+-------------------------------------
+
+## New Features
+ * job-manager: add final flag to sched.free (#6197)
+ * add `-B, --bank=` option to submission commands (#6195)
+ * add flux overlay trace (#6174)
+ * enhance `flux queue list` with `-q, --queue=` option and abillity to
+ report queue enabled/started status (#6185)
+ * support multiple queues in `flux jobs`, `pgrep`, and `pkill` `-q,
+ --queue` option (#6149)
+ * accept `-q` for `--queue` in `flux-jobs`, `pgrep`, and `pkill`
+ (#6142)
+ * resource: mark torpid nodes down for scheduling instead of draining them
+ (#6131)
+ * job-exec: add timeout for job start barrier (#6140)
+ * job-exec: fix per-job `active_ranks` module stats (#6138)
+ * job-exec: fix job refcount leaks (#6134)
+ * drain nodes with unkillable tasks after configurable retries (#6101)
+ * move bad KVS job entries to a lost+found directory (#6139)
+ * add error text to down nodes in flux overlay status (#6111)
+ * job-manager: ignore bad KVS eventlogs (#6129)
+ * add message queue counts to flux module list (#6120)
+ * flux-job: add `-F, --follow` option to `flux job eventlog` (#6102)
+ * wait for job `clean` event by default in `flux run` and `flux job attach`
+ (#6065)
+ * systemd: add prolog/epilog service units (#6040)
+ * broker: work around problem with launch by some versions of mpiexec.hydra
+ (#6081)
+ * reject jobs submitted as user root in a multi-user instance (#6194)
+
+## Fixes
+ * improve housekeeping logging and list management (#6191)
+ * add configure time check for zeromq crypto and improve broker error
+ handling at cert creation (#6189)
+ * resource: error message cleanup, add test for invalid exclude (#6186)
+ * flux-resource: fix missing queue in `flux resource list` output for
+ states with no nodes (#6180)
+ * flux-resource: suppress empty lines in output (#6096)
+ * kvs: return ENOSYS on unfinished requests (#6049)
+ * cmd/startlog: initialize enum to non zero (#6170)
+ * address RSS growth when there are excessive annotation events (#6115)
+ * resource: cache resource status information to reduce broker load (#6105)
+ * flux-start: accept --recovery with --test-size (#6108)
+ * doc: update flux admin guide URL (#6163)
+ * doc: update flux-shell(1) manpage (#6094)
+ * doc: add overlay network to overview section (#6092)
+
+## Cleanup
+ * kvs: minor cleanup (#6172)
+ * job-manager: silence housekeeping debug logs (#6113)
+ * kvs: replace list of message with msglist (#6047)
+
+## CI/Testsuite
+ * matrix/actions: add per-target timeout-minutes (#6192)
+ * t: add initial ENOSPC tests (#6127)
+ * matrix: avoid overwriting env elements (#6190)
+ * docker: Demote fedora40 to `x86_64` only (#6188)
+ * ci: ignore merge errors and increase parallelism (#6183)
+ * testsuite: fix racy test in t2406-job-exec-cleanup.t (#6187)
+ * add support for new wrap options in tests and heredoc support for sharness
+ (#6150)
+ * actions: increase ci timeout from 90 to 120 minutes (#6181)
+ * matrix: fix matrix generation for arm64 and remove redundant fedora
+ (#6156)
+ * Update containers: el9, fedora40, noble, add arm64 for fedora40, el9,
+ noble (#6128)
+ * t: add job environment to tests (#6106)
+
+
+flux-core version 0.64.0 - 2024-07-02
+-------------------------------------
+
+## Experimental Features
+ * job-manager: add support for housekeeping scripts with partial release
+ of resources (#5818)
+
+## New Features
+ * sdexec: add stats-get RPC handler (#6071)
+ * job-exec: add `active_ranks` per-job stats (#6070)
+ * job-list: add support for `ranks` constraint (#6048)
+ * job-list: support "hostlist" constraint to allow jobs to be filtered by
+ nodes (#5656)
+ * add environment variable to avoid `RTLD_DEEPBIND` when loading modules
+ (#6063)
+
+## Fixes
+ * job-manager: improve sched.alloc request tracking (#6076)
+ * flux-job: fix prolog refcount in attach status message #6074
+ * job-exec: fix `active_shells` count in per-job stats (#6070)
+ * job-manager/prioritize: update priority before sending (#6062)
+ * job-exec: do not streq() an unbuffered string (#6058)
+ * python: Update default Jobspec setattr() path (#6053)
+ * shell: enhance exit-timeout and exit-on-error exceptions with hostname
+ (#6056)
+ * libidset: improve efficiency of idset intersection (#6045)
+ * etc: update bash completions (#6039, #6060)
+ * flux-python: add posix-compatible shebang wrapper (#6041)
+ * libsubprocess: use matchtag instead of pid for flux_subprocess_write()
+ (#6013)
+ * sdexec: fix use after free during teardown (#6037)
+ * broker: avoid 60s delay on follower shutdown (#6034)
+
+## CI/Testsuite
+ * t: suppress hwloc 2.10 memleaks (#6061)
+ * ci: convert `system` test container to run under `podman` for better
+ `systemd` support (#6043)
+
+
+flux-core version 0.63.0 - 2024-06-04
+-------------------------------------
+
+## New Features
+ * broker: add timezone abbrev to log message timestamps (#6027)
+ * add output buffering to sdexec (#6023)
+ * libsubprocess: support `FLUX_SUBPROCESS_FLAGS_LOCAL_UNBUF` (#5975)
+ * job-exec: add `kill-signal` and `term-signal` module parameters (#6017)
+ * broker: add tunable parameters for extreme fanout configurations (#6006)
+ * bypass KVS for job stdin with `--input=FILE` (#6005)
+ * flux-dump: add --ignore-failed-read option (#5989)
+ * libsubprocess: improve read API (#5965)
+ * job-manager: journal jobspec with submit event (#5955)
+
+## Fixes
+ * improve broker messages when nodes die (#6032)
+ * sdexec: don't return ENODATA without start/finish (#6033)
+ * speed up `flux overlay status` on large systems (#6030)
+ * librlist: ensure properties is an array when parsing resource.config entries
+ (#6029)
+ * resource: stop scheduler updates during shutdown (#6028)
+ * libsubprocess: reduce remote input prep/check (#6002)
+ * job-exec: retry kill of job tasks and job shell during job termination
+ (#6014)
+ * libsubprocess: protect against double EOF (#6025)
+ * sdexec: avoid double EOF notification (#6022)
+ * job-exec: cmdline options for signals should override config settings
+ (#6020)
+ * job-manager: don't log expiration update when unnecessary (#6016)
+ * libsubprocess: handle remote protocol errors (#6003)
+ * shell: do not fail on oom init failure (#6004)
+ * shell: split up and improve efficiency of input plugin (#5998)
+ * suppress confusing log messages when broker is signaled during shutdown
+ (#5996)
+ * broker: don't post quorum-full in non-QUORUM state (#5994)
+ * shell: fix repeated output truncation warning messages (#5993)
+ * don't free alloc-bypass resources when scheduler reloads (#5980)
+ * flux-job: improve EPERM error message (#5971)
+ * libsubprocess: demote assert to warning (#5959)
+ * job-exec: do not allow guest access to the testexec implementation by
+ default (#5961)
+
+## Documentation
+ * doc: misc man page cleanup (#6008)
+ * doc: fix typo in flux-jobs(1) (#6001)
+ * doc: add PRIORITY state to flux-jobs(1) (#5988)
+
+## Cleanup
+ * libsubprocess: minor cleanup (#5974)
+ * job-manager: misc cleanup in scheduler interface (#5969)
+ * libsubprocess: remove unused len parameter from `flux_subprocess_read()`
+ (#5950)
+ * job-exec: remove layer of stats indirection (#5947)
+
+## CI/Testsuite
+ * testsuite: fix sdexec-memlimit config update test (#6007)
+
+
+flux-core version 0.62.0 - 2024-05-07
+-------------------------------------
+
+## New Features
+ * job-exec: support config reload (#5913)
+ * job-exec: support module stats to see current bulk-exec configuration
+ (#5943)
+ * do not filter caches when loading hwloc topology (#5945)
+ * shell: add `hwloc.restrict` option to restrict `HWLOC_XMLFILE` to assigned
+ resources (#5944)
+ * cleanup resource.eventlog and handle remapped ranks (#5914)
+ * resource: upgrade KVS resource.eventlog if needed (#5936)
+ * flux-resource: add `-q, --queue=QUEUE` option (#5935)
+ * change default tbon.topo to kary:32 (#5930)
+ * flux-job: add `flux job taskmap --to=hosts` (#5941)
+ * notify user of stopped queue in `flux job attach` (#5911)
+ * add options for offline config file parsing (#5907)
+ * flux-exec: set up systemd environment to support sdexec debugging (#5903)
+ * job-list: limit constraint comparisons to avoid DoS (#5681)
+ * broker/module.c: name threads (#5895)
+ * suppress epilog on jobs canceled during shutdown (try no. 2) (#5894)
+
+## Fixes
+ * libsubprocess: reduce remote output prep/check (#5932)
+ * job-exec: fix potential use-after-free in bulk-exec implementation (#5937)
+ * broker: avoid LOST due to EHOSTUNREACH messages during shutdown (#5928)
+ * fix possible use-after-free in chained future implementation (#5927)
+ * job-manager: perilog: do not set working directory on subprocesses (#5922)
+ * cron: fix race if sync event changed or disabled (#5908)
+ * job-manager: improve handling of offline ranks in job prolog (#5910)
+ * Support optional arg in -L (--color) short option (#5890)
+ * alloc-check: account for resources in scheduler hello failure (#5897)
+ * librlist: sort rlist before generating R (#5887)
+ * properly report signaled tasks in `flux job wait` and `flux job attach`
+ (#5886)
+
+## Documentation
+ * doc: convert internals docs to readthedocs (#5939)
+ * doc: enhance core dump instructions in admin guide (#5926)
+ * doc: add pre-flight checklist to admin guide (#5899)
+ * doc: various minor flux-cron(1) fixes and improvements (#5905)
+
+## Cleanup
+ * job-exec: silence nuisance logging (#5948)
+ * assorted minor source cleanup (#5918, #5924)
+
+## CI/Testsuite
+ * docker-run-checks: ensure we match user's home (#5938)
+ * deps/docker: add 'time' as a dependency for tests (#5933)
+ * fix potential segfault in `test_terminus.t` (#5888)
+ * docker: add script help message for macOS (#5779)
+
+
+flux-core version 0.61.2 - 2024-04-12
+-------------------------------------
+
+## Fixes:
+
+ * broker: improve handling of overlay network during shutdown (#5883)
+ * job-manager: canceled job need not wait for sched (#5877)
+ * broker: allow patch versions to interoperate (#5879)
+
+## Testsuite:
+
+ * testsuite: fix `t3203-instance-recovery.t` under `fakeroot` (#5875)
+
+flux-core version 0.61.1 - 2024-04-09
+-------------------------------------
+
+## Fixes:
+
+ * broker: reduce log noise (#5869)
+ * shutdown: unload perilog plugin during shutdown (#5871)
+ * fix broker crash in `resource.status` RPC handling when excluded ranks
+ are also down (#5870)
+ * broker: avoid slow offline child UUID lookup (#5867)
+ * resource: round timestamp of drained ranks (#5866)
+ * fix more performance issues in `flux resource` (#5865)
+ * resource: improve `resource.status` response time with many drained ranks
+ (#5863)
+
+## Cleanup
+
+ * minor cleanup in job-manager journal and job-list (mostly inline docs)
+ (#5850)
+ * job-list: remove jobspec/R update dead code (#5853)
+
+## Documentation
+
+ * doc: add path to 'manpages' to conf.py (#5855)
+ * doc: fix whitespace issues in admin guide (#5854)
+
+flux-core version 0.61.0 - 2024-04-02
+-------------------------------------
+
+## New Features
+
+ * add utility for posting manual job events if required (#5848)
+ * add `--taskmap=hostfile:FILE` support (#5844)
+ * make KVS garbage collection automatic (#5840)
+ * add a faster way to get resource allocation status than
+ sched.resource-status RPC (#5796, #5834)
+ * job-manager: drop sched.free response requirement (#5786)
+ * job-manager: include R in sched.free request (#5783)
+
+## Fixes
+
+ * flux-job: fix `wait-event -m, --match-context`(#5846)
+ * eliminate duplicate KVS restart in job-list and job-manager (#5837)
+ * python: return empty string on epoch time for D conversion flag (#5841)
+ * configure: add missing check for python ply >= 3.9 (#5839)
+ * fix handling of `Ctrl-SPACE` (`NUL`) over job ptys (e.g. under `flux
+ job attach`) (#5833)
+ * job-ingest: fix handling of size > 16K and reserve some FLUID generator
+ IDs for future use (#5831)
+ * fix `flux submit` and `bulksubmit` handling of mustache templates in
+ command and args (#5817)
+ * flux-resource: improve performance of `flux resource list` (#5823)
+ * optimize key librlist functions to improve `flux resource list`
+ performance (#5824)
+ * python: fix handle barrier method to return a Future (#5825)
+ * job-manager: fix infinite loop when loading builtin jobtap plugin (#5822)
+ * flux-top: skip poorly formed job list records (#5821)
+ * job-exec: raise fatal job exception if rank 0 job shell is lost due to
+ signal (#5814)
+ * job-exec: improve cleanup after lost shell events (#5813)
+ * job-exec: fix potential leak of job KVS namespaces (#5805)
+ * job-exec: fix rare segfault at scale due to libsubprocess use-after-free
+ (#5803)
+ * kvs: remove excessive logging (#5804)
+ * modules/content: drop incorrect assertion (#5781)
+
+## Documentation
+ * add doc/requirements.txt to dist (#5852)
+ * doc: add missing R documentation to flux-jobtap-plugins(7) (#5838)
+
+## CI/Testsuite
+
+ * testsuite: fix potential hang in t2812-flux-job-last.t (#5835)
+ * testsuite: fix test racing with exit-timeout (#5810)
+ * python: update required versions of black and mypy (#5808)
+ * testsuite: fix lingering processes after `make check` (#5769)
+ * github: set `kernel.randomize_va_space=0` for asan build (#5802)
+ * github: run asan build on fedora36 (#5800)
+ * testsuite: fix test that kills the wrong processes (#5792)
+ * improve handling of lost job shells (#5780)
+
+
+flux-core version 0.60.0 - 2024-03-05
+-------------------------------------
+
+Note: This release replaces the flux-filemap(1) command with an enhanced new
+command called flux-archive(1). Simple invocations of flux-filemap(1) will
+continue to work for a while to enable migration to flux-archive(1).
+
+## New Features
+ * job-manager: support suppression of prolog/epilog output with
+ `perilog.log-ignore` pattern list (#5772)
+ * flux-job: attach: support MPIR tool launch extension (#5758)
+ * add `flux job hostpids` command (#5765)
+ * shell: support opening output files with `-o output.mode=append` (#5766)
+ * shell: add rexec plugin (#5605)
+ * shell: unset `HWLOC_COMPONENTS` with `hwloc.xmlfile` (#5759)
+ * flux-job: add shorthand paths for `flux job eventlog` and `wait-event`
+ (#5749)
+ * flux-archive: add new command for file broadcast (#5701)
+ * completions: support completion of jobids with plain `f`, support
+ flux-hostlist(1) (#5745)
+ * libtaskmap: support decode of raw (semicolon-delimited) taskmaps (#5735)
+ * shell: make kvs output limit configurable and default single-user jobs
+ to unlimited (#5732)
+ * add flux-hostlist(1) (#5724)
+
+## Fixes
+ * broker: catch an improper use of groups and handle it gracefully (#5762)
+ * shell: fix incorrect values returned from `flux_shell_get_rank_info(3)`
+ (#5756)
+ * shell: generate fatal error if `block` taskmap scheme has an argument
+ (#5730)
+ * do not drain ranks when job is canceled during prolog (#5742)
+ * optparse: fix segfault when subcommand registration fails due to invalid
+ options table (#5740)
+ * fix various typos (#5761)
+
+## Documentation
+ * doc: pull in admin guide (#5763)
+
+## Cleanup
+ * fix various typos (#5761)
+ * libsubprocess: minor API cleanup (#5699)
+ * cmd: split flux-job into separate source files (#5747)
+ * job-info: support lookup of updated jobspec, remove manual construction
+ of updated R / jobspec (#5635)
+ * job-info: add `JSON_DECODE` & `CURRENT` flags, deprecate
+ job-info.update-lookup (#5633)
+
+## Build/Testsuite
+ * github: update deprecated actions (#5768)
+ * testsuite: fix t2617 to utilize /dev/urandom (#5757)
+ * testsuite: fix random-generation of kvs archive files in t0021 (#5751)
+
+
+flux-core version 0.59.0 - 2024-02-06
+-------------------------------------
+
+## New Features
+ * broker: add `FLUX_IPADDR_INTERFACE` to select broker network interface
+ (#5707)
+ * python: support interface to perform KVS watch (#5389)
+ * python: support Python 3.12 (#5691)
+ * broker: allow single-user rexec to rank 0 (#5677)
+ * add -x option to flux-alloc and flux-batch (#5665)
+ * add flux filemap get --overwrite and change the default overwrite behavior
+ (#5662)
+ * shell: add shell.post-init plugin calllback topic between shell.init
+ and first task.init (#5179)
+ * pmi: prepend Flux PMI directory to `LD_LIBRARY_PATH` (#5715)
+ * shell: write hwloc XML to a file with `HWLOC_XMLFILE` set with
+ `-o hwloc.xmlfile` (#5721)
+
+## Fixes
+ * job-list: initialize queue stats (#5712)
+ * job-ingest: fix FLUID initialization error handling to allow scaling
+ beyond 16K brokers (#5710)
+ * python: fix `flux-watch: TypeError: Object of type 'bytes' is not JSON
+ serializable` (#5704)
+ * enable encode of pty data as base64 and make `flux alloc vi` test more
+ reliable (#5703)
+ * librlist: workaround xml buffer size issue in some hwloc versions (#5690)
+ * librlist: fix segfault when initializing topology from XML in later
+ hwloc versions (#5682)
+ * fix broker hang under `flux proxy` (#5680)
+ * set userid to instance owner in job manager exceptions (#5675)
+ * job-manager: fix duplicate posting of jobspec-update event from plugins
+ (#5673)
+ * broker: only set parent-uri when instance is a job (#5663)
+ * kvs: store correct namespace after getroot lookup (#5661)
+
+## Documentation
+ * docs: add `flux_msg_incref` manpage (#5624)
+ * doc: correct typo in `flux_requeue(3)` (#5660)
+
+## Cleanup
+ * libsubprocess: make `flux_buffer` class private (#5683)
+ * job-list: misc cleanup (#5687)
+ * drop the flux-mini command (#5666)
+ * libsubprocess: minor clean up (#5667)
+
+## Build/Testsuite
+ * test: add some scaling test support (#5717)
+ * github: update checkout action to v4 to silence warnings (#5716)
+ * docker: add Dockerfile for fedora39 (#5713)
+ * ci: add fedora39 build (#5698)
+ * testsuite: fix testsuite errors discovered in conda-forge build
+ environment (#5685)
+ * drop jsonschema requirement (#5678)
+ * libpmi: add `JANSSON_CFLAGS` to Makefile.am (#5672)
+
+
+flux-core version 0.58.0 - 2024-01-04
+-------------------------------------
+
+## New Features
+ * flux-batch: support `--quiet` option (#5645)
+ * resource: get local hwloc XML from parent when possible (#5636)
+ * python: Add `kvs.commit_async()` (#5627)
+ * python: add `decode` method to Flux `Message` class (#5653)
+ * python: add rolemask parameter to `msg_handler_create()` (#5650)
+
+## Fixes
+ * libflux: respond to denied, matchtagless requests (#5652)
+ * minor updates and improvements to bash completions (#5647)
+ * broker: improve handling of interactive initial programs (#5646)
+ * resource: fix initialization of multiple brokers per node when fallback
+ to job-info.lookup is used (#5639)
+ * libflux: add include for `ssize_t` to message.h (#5638)
+ * libflux: don't accept `FLUX_MSGTYPE_ANY` in `flux_msg_create()` (#5631)
+ * job-list: fix json object mem-leak (#5626)
+ * job-list: fix `flux job list-ids --wait-state` (#5620)
+
+## Documentation
+ * doc: add missing standard-io options to flux-batch(1) (#5648)
+ * doc: expand glossary (#5634)
+ * doc: reference flux-environment(7) in job submission cli man pages (#5629)
+ * misc doc fixes (#5604)
+
+## Cleanup
+ * libflux: drop `flux_msg_frames()` (#5632)
+ * libflux: deprecate some message flag accessors and add new and improved
+ ones (#5630)
+ * maint: remove flux spack docker (#5628)
+
+## Testsuite
+ * testsuite: fix fileref unit test failure on tmpfs (#5643)
+ * testsuite: avoid artificial corefile in test (#5641)
+ * testsuite: fixes for Lassen (#5551)
+ * testsuite: fix test corner case on stderr (#5625)
+ * testsuite: more reliability improvements in tests (#5621)
+ * testsuite: fix t2260-job-list.t with `-d -v` and run inception tests
+ with these args to prevent future similar errors (#5618)
+ * libkvs: fix test failure in aarch64 CI (#5617)
+ * testsuite: fix t2233-job-info-update.t with debug=t (#5616)
+
+
+flux-core version 0.57.0 - 2023-12-07
+-------------------------------------
+
+## New Features
+ * support colorized, human-readable output from eventlog commands (#5602)
+ * python: add KVSTxn class to KVS module (#5374)
+ * libidset: implement API for integer allocator use case (#5580)
+ * port to Alpine linux (#5568)
+ * job-ingest: make worker input buffer configurable with a default of 10MB
+ (#5550)
+
+## Fixes
+ * kvs: limit the content of guest commits (#5612)
+ * history: track root jobs (#5608)
+ * improve ssh connector reliability with different installation paths (#5591)
+ * flux-terminus: fix potential hang in terminus client commands (#5607)
+ * support start under older versions of Flux without the
+ job-info.update-watch RPC (#5589)
+ * kvs-watch: improve performance of kvs-watch disconnect/cleanup handling
+ (#5585)
+ * cli: avoid KeyError when PATH isn't set in environment (#5590)
+ * broker: eliminate some message copies (#5559)
+ * libidset: improve decoding functions (#5584)
+ * fix improper include directives in source files impacting portability
+ (#5567)
+ * make flux Python commands more resilient to changes in PYTHONPATH (#5553)
+ * job-ingest: fix cleanup when a pipeline worker process fails (#5549)
+ * libsubprocess: do not allow short writes with `flux_subprocess_write()`
+ (#5548)
+ * flux-submit: fix substitution of `{cc}` when cc=0 (#5541)
+
+## Documentation
+ * doc: use common format for commands with sub-commands (#5597)
+ * flux-kvs(1): improve man page formatting (#5588)
+ * clean up idset man pages (#5578)
+ * doc: improve --urgency option description in job submission commands
+ (#5571)
+ * doc: improve RFC references in man pages (#5573)
+ * man3: add Link with... instruction to SYNOPSIS (#5574)
+ * flux-shell(1): improve option descriptions and x-ref (#5557)
+ * doc: remove options from flux-alloc(1) et al that don't work (#5555)
+ * flux-pmi(1): add new manual page (#5554)
+ * flux-start(1): add more description and troubleshooting info (#5552)
+
+## Build
+ * build: reduce minimum jansson version to 2.9 (#5546)
+ * build: add libmissing, a convenience library for replacements for missing
+ functions (#5560)
+
+## Cleanup
+ * deprecate flux job cancel and improve flux-job(1) documentation (#5587)
+ * job-info: misc cleanup (#5586)
+ * broker: cleanup up attribute initialization code (#5543)
+
+## Testsuite
+ * testsuite: fix some test races and improve debugging (#5609)
+ * testsuite: fix race in job info update lookups (#5598)
+ * testsuite: improve reliability of a couple job signal/cancel tests (#5599)
+ * testsuite: fix fancy f grep inconsistency (#5576)
+ * get sharness tests working on alpine linux (#5564)
+ * testsuite: add multiple key job-info lookup tests (#5575)
+ * ci: add alpine Dockerfile and CI build (#5565)
+
+
+flux-core version 0.56.0 - 2023-11-07
+-------------------------------------
+
+## New Features
+
+ * support duration update for running jobs (#5522)
+ * job-list: support resource-update event (#5463)
+ * flux-job: get updated version of R (#5464)
+ * cache R in the job manager (#5472)
+ * job-info: support new update-lookup and update-watch service (#5467)
+ * libflux: make local connector built-in (#5504)
+ * make the loop:// connector built-in rather than a DSO (#5486)
+ * libflux: add `flux_send_new()` (#5499)
+ * add interthread connector that does not require zeromq (#5495)
+ * broker: use interthread connector between broker modules (#5496)
+
+## Fixes
+
+ * fix job submission to a multi-user instance over flux-proxy (#5533)
+ * job-manager: fix error message on duplicate plugin load (#5537)
+ * set `FLUX_PMI_LIBRARY_PATH` only in the job environment when simple pmi
+ is active (#5535)
+ * job-exec: fix potential hang after exec kill error (#5534)
+ * flux-proxy: fix double-free on lost connection (#5529)
+ * cron: handle ENOMEM without asserting (#5515)
+ * connectors: avoid future ABI issues with `_pad[]` (#5505)
+ * python: return more precise result from `flux.util.parse_datetime("now")`
+ (#5507)
+ * python: fix handling of JobInfo properties and `to_dict()` method with
+ missing attributes (#5493)
+
+## Documentation
+
+ * flux-environment(7): add new man page (#5527)
+ * man1: improve HTML formatting of man pages (#5521)
+ * man3: improve HTML formatting of man pages (#5517)
+ * man3: improve HTML formatting of SYNOPSIS sections and C examples (#5503)
+ * python: add flux.job.list docstrings (#5500)
+ * doc: add interacting with flux section (#5492)
+
+## Cleanup
+
+ * drop broker `conf.module_path`, `conf.connector_path`, `conf.exec_path`
+ attributes (#5536)
+ * flux job info: drop multiple key support, clean up code, add man page
+ entry (#5520)
+ * build: reduce junk content in DSOs (#5516)
+ * shell: drop job shell standalone mode (#5512)
+ * misc build system cleanup (#5511)
+ * libflux: refactor internal message queues (#5508)
+
+## Testsuite
+
+ * testsuite: trivial test fixes (#5498)
+ * ci: add flux-pmix, flux-pam builds to CI (#5489)
+
+
+flux-core version 0.55.0 - 2023-10-03
+-------------------------------------
+
+## New Features
+
+ * drop libzcmq dependency (#5468)
+ * allow hwloc topology to be loaded from a file with `FLUX_HWLOC_XMLFILE`
+ (#5462)
+ * improve begin-time representation in `flux-jobs(1)` output (#5473)
+ * support update of job queue (#5424)
+ * job-list: support getting job project and bank (#5413)
+ * flux-job: get updated version of jobspec (#5428)
+ * flux-top: use streaming job-stats RPC (#5432)
+ * job-list: support streaming job-stats RPC (#5430)
+
+## Fixes
+
+ * libzmqutil: fix portability to libzmq-4.1.5 (#5481)
+ * broker: move policy config check out to the modules that rely on it
+ (#5478)
+ * libzmqutil: add cert class and use it instead of CZMQ `zcert_t` (#5461)
+ * broker: stop managing 0MQ sockets with czmq (#5454)
+ * use zeromq interfaces directly where possible instead of via czmq (#5458)
+ * rc: fix `flux start` failure when multiple scripts are present in `rc1.d`
+ (#5453)
+ * rc: avoid startup problems when `BASH_ENV` is set (#5448)
+ * flux-keygen: drop libsodium requirement (#5446)
+ * content: make the content cache a broker module (#5435)
+ * job-manager: correct fsd output in error message (#5437)
+ * modules: consistently return error on invalid module arguments (#5442)
+
+## Documentation
+
+ * doc: add a page on starting Flux (#5477)
+ * doc: add build instructions and support info (#5476)
+ * doc: add content to landing page and group man pages (#5470)
+
+## Cleanup
+
+ * libflux: drop `flux_panic()` (#5439)
+ * job-manager: update: cleanup, small fixes, and documentation (#5434)
+ * job-manager: stop publishing job-state event messages (#5433)
+
+## Build/Testsuite/CI
+
+ * switch qemu-user-static setup to fix setuid (#5469)
+ * etc: remove ubuntu build-container action (#5474)
+ * configure: use distutils if available to avoid extra python module
+ dependency (#5459)
+ * configure: avoid use of deprecated python distutils module (#5456)
+ * testsuite: handle job signal race in more tests (#5438)
+ * testsuite: increase sleep time in tests (#5431)
+
+
+flux-core version 0.54.0 - 2023-09-05
+-------------------------------------
+
+## New Features
+ * flux-perilog-run: support prolog and epilog timeouts (default 30m) (#5416)
+ * cmd: add --with-imp options to flux-exec(1) and flux-perilog-run(1)
+ (#5422)
+ * shell/pmi: warn if application might be using slurm's libpmi2.so (#5420)
+ * job-list: allow updates to all of jobspec (#5418)
+ * job-manager: support jobspec update to all fields (#5419)
+ * python: add namespace support to KVS module (#5373)
+ * add job update service and new job-update(1) command (#5409)
+ * job-list: support jobspec-update event (#5408)
+ * job-manager: prevent jobspec-update events after a job has resources
+ (#5406)
+ * job-manager: add flux_jobtap_jobspec_update_pack(3) (#5386)
+
+## Fixes
+ * cmd: flux-perilog-run: avoid running prolog/epilog on offline ranks (#5417)
+ * job-manager: fix duration limit check for jobs with unset/unlimited
+ duration (#5405)
+ * flux-top: fix title when connected to instances that are not jobs (#5394)
+ * do not search for module and connector DSOs recursively (#5390)
+ * python: fix __delitem__ in KVSDir with initial paths (#5376)
+ * python: have kvs.isdir() return False if key missing (#5371)
+ * python: clear kvs txn after all commits (#5369)
+
+## Cleanup
+ * libpmi: cleanup old code and optimize client reads (#5423)
+ * job-list: misc cleanup (#5407)
+ * broker: refactor broker module loading code and fix minor bugs (#5385)
+
+## Build/Testsuite/CI
+ * ci: fix failure detection builds with coverage and remove obsolete system
+ tests (#5421)
+ * actions: update typo checker version (#5410)
+ * extend ci-checks timeout for arm64 build (#5402)
+ * testsuite: handle job signal race in more tests (#5401)
+ * matrix: add arm64 install-only builder (#5396)
+ * testsuite: relax systemctl output parsing (#5388)
+ * testsuite: fix race in t0005-exec.t signal test (#5383)
+ * actions: add merge_group trigger (#5379)
+ * mergify: remove status check conditions from config (#5381)
+ * docker-deploy: only push latest when arch is 64-bit (#5377)
+ * docker: drop bionic, el7 and fedora35 for bookworm and fedora38 (#5370)
+
+flux-core version 0.53.0 - 2023-08-01
+-------------------------------------
+
+## New Features
+ * add capability to run jobs in systemd (#5197)
+ * job-exec: allow job memory limits to be set (#5359)
+ * python: add API for job output (#5332)
+ * python: add JobWatcher class and use for `submit` and `bulksubmit`
+ `--watch` functionality (#5357)
+ * cmd: add flux-watch(1) (#5360)
+ * python: add FutureExt class for extensible futures from python (#5330)
+ * shell: support `-o gpu-affinity=map:LIST` (#5356)
+ * job-info: support WAITCREATE on eventlog watch (#5358)
+ * job-list: support job list constraints (#5126)
+
+## Fixes
+ * job-list: support older RPC protocol (#5364)
+ * job-manager: prevent jobs with outstanding epilog-start events from
+ becoming inactive (#5353)
+ * ensure flux utilities agree that a job with a fatal exception has failed
+ (#5355)
+ * flux-job: suppress the `attach` status line in more situations (#5354)
+ * flux-jobs: correct several filtering corner cases (#5164)
+ * sdexec: fix memory leaks (#5349)
+ * python: fix potential gc of Future ffi handle before Future destruction
+ (#5346)
+ * resource: fix problem with exclusions when R is dynamically discovered
+ (#5339)
+ * python: clear KVS txns on commit error (#5335)
+ * python: do not return int status in kvs functions (#5329)
+ * python: fix exists in KVSDir with initial paths (#5331)
+ * python: fix writes in KVSDir with initial paths (#5322)
+ * flux-job: fix invalid --original info output (#5318)
+ * flux-job: fix `flux job status` handling of nonfatal exceptions (#5320)
+ * job-manager: fix prolog/epilog exception handling (#5321)
+ * job-info: ignore duplicate lookup keys (#5317)
+
+## Cleanup
+ * job-exec: remove systemd exec prototype (#5348)
+ * job-manager: make exception note a requirement (#5336)
+ * resource: ignore live resource.exclude changes (#5341)
+ * python: add extra documentation to kvs.py module (#5328)
+
+## Build/Testsuite/CI
+ * testsuite: remove get-xml-test.py (#5340)
+
+
+flux-core version 0.52.0 - 2023-07-06
+-------------------------------------
+
+## New Features
+
+ * libjob: export `flux_unwrap_string(3)` function (#5312)
+ * job-manager: add alloc-check plugin (#5304)
+ * add f58plain job encoding (#5297)
+ * libsubprocess: support user friendly error string (#5294)
+ * python: support convenience API for `job-info.lookup` RPC
+ and `flux job info` (#5265, #5311)
+ * support `[kKMG]` suffixes in command options that take a bytes argument
+ (#5277)
+ * libutil: add `parse_size()` (#5262)
+ * flux-resource: add `R` subcommand (#5246)
+ * job-exec: always use stdio for exec barrier (#5267)
+ * sdbus: make debug logging configurable (#5264)
+
+## Fixes
+
+ * job-manager: publish event on jobtap exception (#5310)
+ * librlist: fix RFC31 corner cases (#5137)
+ * testsuite: workaround job start signal race (#5302)
+ * shell: document signal race (#5299)
+ * testsuite: fix occasional broker kill error (#5291)
+ * do not suppress job shell and broker errors with `flux alloc` (#5274)
+ * allow guests to use flux module list, flux module stats (#5280)
+ * broker: load module with DSO version extension (#5283)
+ * shell: ensure captured pty data does not come after stdout EOF in output
+ eventlog (#5282)
+ * Parse jobspec attributes.system optionally (#5279)
+ * broker: avoid spurious overlay peer warning (#5275)
+ * flux-resource: fix `-i, --include=HOSTS` in `list` command when some
+ hosts are excluded (#5268)
+ * python: allow JobID to take a JobID (#5259)
+ * flux-top: fix formatting with ASCII jobids (#5263)
+ * shell: set correct HOSTNAME in job environment if necessary (#5261)
+ * Ignore errors when starting flux from a restart dump containing giant
+ blobs (#5254)
+ * support utf-8 in broker logs (#5253)
+ * flux-config-bootstrap(5): fix TOML error (#5252)
+ * libjob: return on error in `unwrap_string()` (#5251)
+ * libjob: fix leak in `sign_unwrap()` (#5248)
+ * flux-job: fix attach notification with multiple prolog-start events (#5315)
+
+## Cleanup
+
+ * switch from decimal to f58 jobid encoding in most log messages and shell
+ service name (#5256)
+ * flux-job: add missing include of signal.h (#5247)
+ * testsuite: improve alloc-check test (#5309)
+ * fix assorted typos and adjust whitespace per project norms (#5298)
+
+## Build/Testsuite/CI
+
+ * build: require flux-security >= 0.9.0 (#5270)
+
+flux-core version 0.51.0 - 2023-06-09
+-------------------------------------
+
+This release adds the flux-batch(1) and flux-alloc(1) `--conf` option,
+which makes subinstance configuration significantly easier. Sys admins
+may note that _named configurations_ can be added to `/etc/xdg/flux/config`
+for configurations that are anticipated to be commonly needed such as
+node-exclusive scheduling.
+
+For example, `/etc/xdg/flux/config/node-exclusive.toml` could contain:
+```toml
+[sched-fluxion-resource]
+match-policy = "lonodex"
+```
+And then users could request this in a batch subinstance with:
+```
+flux batch --conf=node-exclusive ...
+```
+
+## New Features
+
+ * add `--conf` option for registering instance config in `flux-batch` and
+ `flux-alloc` (#5232)
+ * support RFC 14 `files` file archive in jobspec, add `--add-file` option
+ to cli submission commands (#5228, #5239)
+ * support option to signal a job a configurable time before expiration (#5212)
+ * flux-resource: add `-i, --include` option to filter hosts for `status`
+ and `drain` commands (#5219)
+ * flux-resource: add `-i, --include=TARGETS` option to `list` and `info`
+ subcommands (#5236)
+ * broker: forward nonfatal signals to all running jobs (#5202)
+ * broker: unset `SLURM_*` in initial program environment (#5237)
+ * sdbus: add subscription filtering (#5227)
+ * job-exec: provide IMP exec helper when possible and use stdin/out for
+ shell exec protocol (#5186)
+ * support emoji encoding for Flux jobids (#5174)
+ * job-list: support retrieving current working directory for jobs (#5156)
+ * job-list: allow list-id to wait for job state (#5213)
+ * flux-jobs: support new `inactive_reason` output field and `endreason`
+ format (#5055)
+ * broker: redefine broker.quorum as a size (#5153)
+ * broker: signal readiness to systemd in JOIN state (#5152)
+
+## Fixes
+
+ * completions: update bash completions with recent command changes (#5241)
+ * shell/pmi: accept pmi1 and pmi2 as aliases for "simple" pmi (#5242)
+ * `zhash_insert()`/`zhashx_insert()` return EEXIST (#5217)
+ * restrict remote access to sdbus on rank 0 (#5162)
+ * flux-job: submit: strip unnecessary whitespace from pre-signed jobspec
+ (#5185)
+ * libsubprocess: fail with ESRCH when pid cannot be found (#5229)
+ * flux-jobs: reduce likelihood of leaving bad terminal color state on
+ empty output (#5211)
+ * python: support non-JSON formatted data in KVS (#5204)
+ * Add missing include of config.h (#5182)
+ * liboptparse: correct message on missing argument (#5180)
+ * python: improve handling of `!d` conversion specifier in output formats
+ (#5169)
+ * libioencode: fix memleaks on error paths (#5159)
+ * shell: add missing `flux_` prefix to `shell_mustache_render(3)` (#5161)
+ * shell: truncate output to KVS after 10MB (#5155)
+ * python: open UtilConfig files as binary (#5157)
+ * job-manager: make some replay errors non-fatal (#5150)
+ * doc: fix python example (#5191)
+ * flux-job: ignore stdin instead of aborting when unable to create stdin
+ watcher (#5183)
+
+## Cleanup
+ * cleanup: use ccan/str in place of strcmp(), strncmp() (#5163)
+ * job-list: misc cleanup (#5144)
+
+## Testsuite/CI
+ * testsuite: fix potential flux-top race (#5224)
+ * testsuite: fix tests when run in debug mode (#5231)
+ * testsuite: increase test expiration (#5222)
+ * testsuite: fix race in flux top tests (#5194)
+ * testsuite: skip tests that expect COLUMNS to be inherited across calls
+ to flux(1) when that isn't true (#5166)
+ * pre-commit: increase vermin version (#5173)
+ * ci: fix pre-commit config to lint python files in testsuite (#5221)
+ * ci: add fedora38 builder, update flux-security default to 0.8.0 (#5160)
+
+flux-core version 0.50.0 - 2023-05-03
+-------------------------------------
+
+## New Features
+ * broker: make `tbon.connect_timeout` configurable (#5140)
+ * flux-job: support job ids to purge (#5047)
+ * sdbus: enable flux to communicate with a systemd user instance (#5070, #5131)
+ * shell: support `{{name}}` tag in output file templates (#5128)
+ * flux-top: support ability to flip through queues via left/right arrow keys
+ (#5052)
+ * flux-ping: output header before output of main ping output (#5034)
+ * broker: improve systemd integration with `sd_notify(3)` (#5078)
+
+## Fixes
+ * `flux(1)`: avoid prepending to PATH when unnecessary (#5138)
+ * python: make `SchedResourceList` optional in `flux.job.info` (#5141)
+ * fix parent-uri attribute under remote `flux-proxy(1)` (#5133)
+ * job-list: make job stats consistent to job results (#5048)
+ * fileref: fix compile on systems without `SEEK_DATA`/`SEEK_HOLE` (#5114)
+ * fixes for build/test on Fedora 36 (GCC 12) (#5107)
+ * shell: fix improper encoding of some hostnames in MPIR proctable (#5117)
+ * python: fix parsing of special characters in submission directives (#5125)
+ * job-validator: fix empty plugins list when one plugin fails to import
+ (#5124)
+ * broker: use human readable timestamp in local time when logging to stderr
+ (#5129)
+ * improve error on plugin load if `flux_plugin_init()` returns an error
+ (#5135)
+ * librlist: fix memleak + misc cleanup (#5110)
+ * sched-simple: avoid assertion failure when trying to load scheduler twice
+ (#5109)
+ * job-manager: improve errors from jobtap initialization (#5099)
+ * libsubprocess: avoid segfault on error path (#5096)
+ * job-exec: improve error message when job shell/imp execution fails (#5088)
+ * systemd: avoid leaving unit in failed state after flux-shutdown(1) (#5077)
+
+## Cleanup
+ * libjob: deprecate `flux_job_list()` and `flux_job_list_inactive()` (#4855)
+ * broker: clean up module infrastructure (#5085)
+ * libsubprocess: remove use of assert(0) (#5084)
+
+## Testsuite/CI/Development
+ * ensure license and other informational files appear in distribution
+ tarball (#5113)
+ * mergify: add spelling check to required checks (#5112)
+ * Add false positives typos config (#5106)
+ * Fix minor typos and formatting (#5019)
+ * testsuite: fix test issues under nix (#5015)
+ * testsuite: fix column width output corner case (#5103)
+ * testsuite: fix setup error in system tests (#5102)
+ * build: add `make deb` target to build test debian package (#5101)
+ * build: applicable build and test fixes for conda (#5093)
+ * testsuite: skip failing test on RHEL7 (#5090)
+ * add spell check for news, readme, and user facing code (#5074)
+
+
+flux-core version 0.49.0 - 2023-04-05
+-------------------------------------
+
+## New Features
+ * libpmi: improve error messages from upmi plugins (#5066)
+ * shell: support -o pmi=LIST (#5069)
+ * flux-jobs: add --json option (#5054)
+ * flux-job: add special exit code to flux job wait when not waitable (#5049)
+ * libpmi: enable flux to bootstrap with cray libpmi2.so (#5051)
+ * libpmi: improve tracing of dlopened PMI libraries (#5053)
+ * resource: do not allow ranks to be both drained and excluded (#5039)
+ * Support environment variable to override default output formats (#5028)
+ * improve broker debugging on overlay connect failure (#5014)
+ * rewrite flux-resource status (#4997)
+ * flux-resource: support overwrite of drain timestamp with `--force --force`
+ (#5000)
+ * python: improve Hostlist class indexing (#4993)
+
+## Fixes
+ * openmpi: don't force flux MCA plugins (#5067)
+ * PMI: ensure fallthrough when PMI library fails to initialize (#5058)
+ * flux-top: fix queue specific output display (#5032)
+ * flux-pgrep: fix warning about `sre_constants` on Python 3.11+ (#5043)
+ * prevent orphaned job processes when terminating jobs due to exception
+ (#4990)
+ * python: recognize local timezone epoch adjustment (#5025)
+ * fix rare `Unable to connect to JOBID` error from `flux alloc --bg` (#5012)
+ * job-manager: ensure epilog-start event prevents resource release for
+ job that never started (#5011)
+ * librlist: drop V1 flag from hwloc XML generation (#5007)
+ * fix: warning message to user should be actual command (#5002)
+ * flux-mini: improve deprecation warning (#4989)
+
+## Cleanup
+ * job-list: minor code consistency cleanup (#5031)
+ * mpi: drop mvapich.lua plugin (#5045)
+ * libflux: remove extraneous +1s used in buffers (#5020)
+ * cleanup: improve interface for subprocess logging (#5006)
+ * cleanup: simplify remote subprocess protocol (#5004)
+ * cleanup: allow subprocess service name to be configured (#5003)
+ * cleanup: improve reusability of common message handlers (#5001)
+
+## Documentation
+ * flux-job(1): update WAIT section (#5042)
+ * doc: document job environment variables (#5024)
+ * doc: document `FLUX_URI_RESOLVE_LOCAL` (#5023)
+ * cli: adjust description of `--begin-time` submission option (#5018)
+
+## Testsuite/CI/Development
+ * testsuite: increase test timeouts (#5017)
+ * testsuite: speed up t4000-issues-test-driver.t (#5010)
+ * testsuite: require jq(1) (#4995)
+
+
+flux-core version 0.48.0 - 2023-03-07
+-------------------------------------
+
+This release adds submission directives ("see flux help batch") and
+shortens the the job submission commands to "flux batch", "flux run",
+etc. The flux-mini(1) command is deprecated.
+
+## New Features
+
+ * support RFC 36 submission directives in `flux mini batch` (#4942)
+ * make all flux-mini subcommands available as top level flux commands (#4961)
+ * add flux-cancel(1) (#4983)
+ * add flux-fortune (#4966)
+ * flux-run: allow stdin to be directed to a subset of tasks (#4977)
+ * cmd: add -u, --unbuffered option to submission commands (#4973)
+ * allow flux-core to be configured in ascii-only mode (#4968)
+ * Support {{tmpdir}} in shell mustache templates and simplify batch jobspec
+ construction (#4951)
+ * broker: allow a file argument to `-c, --config-path` in TOML or JSON
+ (#4949)
+
+## Fixes
+
+ * completions: remove flux-mini and other updates (#4984)
+ * flux-top: initialize f character before drawing panes (#4982)
+ * libsubprocess: don't abort remote processes that receive SIGSTOP (#4981)
+ * shell: fix memory leak in doom plugin (#4979)
+ * flux-resource: suppress NGPUS on systems without GPUs (#4959)
+ * job-ingest: handle worker channel overflow (#4948)
+ * improve error message in Python frontend utilities when broker is not
+ running (#4950)
+ * job-manager: fix for job priority not reset after a duplicate urgency
+ update (#4941)
+ * job-manager/history: track inactive jobs over purge/restart (#4932)
+
+## Cleanup
+
+ * flux-filemap: update to RFC 37 internally (#4974)
+ * libsubprocess: rework internal logging (#4960)
+ * libsubprocess: drop `FLUX_SUBPROCESS_EXEC_FAILED` state (#4955)
+ * libsubprocess: fix bugs and clean up subprocess server (#4944)
+
+## Documentation
+
+ * Fix minor documentation errors and typos (#4934)
+ * flux-batch(1) and flux-alloc(1): improve DESCRIPTION section (#4963)
+ * README: fix a couple typos (#4970)
+ * README: trim it down now that we have readthedocs (#4969)
+ * divide flux(1) help output into sections (#4967)
+ * doc: add shell help on flux-jobs(1) formatting (#4939)
+ * doc: document attach in flux-job(1) (#4936)
+
+## Testsuite/CI/Development
+
+ * testsuite: unset `FLUX_F58_FORCE_ASCII` in some tests (#4976)
+ * .devcontainer permissions fix (#4964)
+ * Add/developer doc on commands (#4965)
+
+flux-core version 0.47.0 - 2023-02-07
+-------------------------------------
+
+## New Features
+
+ * add `flux job last` (#4908)
+ * add `flux-pgrep` and `flux-pkill` (#4867, #4903)
+ * add `flux-keygen --meta KEY=VAL` option (#4882)
+ * add tools for querying job remaining time: `flux_job_timeleft(3)`, python
+ `flux.job.timeleft()` and `flux-job timeleft` (#4845)
+ * flux-shell: add `-opmi=off` option (#4841)
+ * suggest use of `--force` in `flux resource drain` when target is already
+ drained (#4924)
+ * automatically provide job status for pending interactive jobs (#4916)
+ * flux-resource: mark drained+offline nodes with asterisk (#4913)
+ * support flux mini batch,alloc `--dump[=FILE]` (#4881)
+ * flux-queue: support flux queue list (#4896, #4929)
+ * support RFC 31 `hostlist` and `rank` job constraints (#4895, #4919)
+ * python: add flux.constraint.parser for RFC 35 Constraint Query Syntax
+ (#4871, #4925)
+ * Support RFC 35 constraint syntax in `flux mini --requires` (#4897, #4923)
+ * flux-top: limit jobs and summary to specific queue (#4847)
+ * enable broker bootstrap methods to be provided by dso plugins, and drop
+ compiled-in pmix support (#4865)
+ * flux-resource: support QUEUE output in resource list (#4859)
+ * flux-top: Support --color option (#4840)
+ * libutil: support "infinity" in FSD (#4846)
+ * add internal universal PMI client library (#4829)
+ * job-manager: default queues to enabled and stopped (#4857)
+ * libtaskmap: add `TASKMAP_ENCODE_RAW_DERANGED` (#4838)
+
+## Fixes
+
+ * job-list: do not assume alloc event context always contains annotations
+ (#4907)
+ * job-manager: fix alloc-bypass plugin (#4901)
+ * flux-resource: increase width of queue field (#4905)
+ * eliminate "safe mode" after improper shutdown (#4898)
+ * flux-resource: handle queues with no configured constraints (#4893)
+ * fix message encoding problem introduced in v0.46.1 (#4890)
+ * flux-shell: truncate long log messages (#4878)
+ * job-manager: switch to timer watcher in perilog plugin (#4864)
+ * job-manager: do not checkpoint on every queue state change (#4856)
+ * job-list: separate `t_submit`/`t_depend` calculation (#4853)
+ * flux-top: honor `FLUX_F58_FORCE_ASCII` (#4842)
+ * flux-job: fix potential segfault (#4827)
+ * work around fluxion inbability to recover running jobs (#4894)
+ * etc: update bash completions (#4928)
+
+## Documentation
+
+ * doc: document `--job-name` in flux-mini(1) (#4879)
+ * doc: document format fields in flux-resource(1) (#4850)
+ * doc: document subcommand `wait` in flux-job(1) (#4851)
+
+## Testsuite/CI/Development
+
+ * clean up little used broker attribute functionality (#4870)
+ * flux-queue: rewrite in python (#4889)
+ * job-list: add jobspec and R parsing unit tests (#4883)
+ * flux-top: add extra test coverage (#4833)
+ * testsuite: increase `flux job wait-event` timeout (#4888)
+ * testsuite: drop fragile broker.boot-method test (#4876)
+ * docker: add site-packages to default python3 path (#4880)
+ * ci: speed up coverage builds (#4828)
+
+
+flux-core version 0.46.1 - 2022-12-11
+-------------------------------------
+
+## Fixes
+ * build: fix installation of libpmi.so (#4824)
+ * testsuite: fix failure on a system with fully-qualified hostname (#4825)
+
+## Cleanup
+ * libflux/message: cleanup with macros and CCAN pushpull class (#4823)
+
+flux-core version 0.46.0 - 2022-12-10
+-------------------------------------
+
+## New Features
+ * job-manager: support start / stop of individual queues (#4776)
+ * add file broadcast toolset (#4789, #4818)
+ * flux-pmi: add installed PMI test tool (#4817)
+ * flux-mini: add --cwd option (#4811)
+ * add flux start --recovery (#4783)
+ * support cyclic, manual job taskmaps and `flux job taskmap` command (#4772)
+ * shell: remove `pmi.clique` option, add `pmi.nomap` (#4785)
+ * libtaskmap: support RFC 34 unknown task maps (#4788)
+ * python: add `flux.job.get_job` (#4761)
+ * allow guests to access flux configuration (#4766)
+ * job-list: add inactive purge count to job-list stats (#4756)
+ * shell: allow users to map specific cpus to tasks with `map` cpu-affinity
+ option (#4819)
+
+## Fixes
+ * broker: fix startup failure when broker.mapping is not set (#4781)
+ * encode broker.mapping as RFC 34 taskmap, drop unused pmi clique helper
+ code (#4787)
+ * add missing taskmap pkg-config file (#4782)
+ * broker: fix potential crash after sending SIGKILL to job-manager prolog
+ (#4793)
+ * broker: improve detection of interactive shells (#4795)
+ * flux-job: remove `finish_mpir_interface()` (#4808)
+ * libhostlist: fix 8K limit on encoded hostlists (#4803)
+ * add flux.taskmap to PMI kvs for better cyclic task distribution
+ scalability (#4798)
+ * job-manager: fix memory corruption due to json reference counting bug
+ (#4773)
+ * python: by default return all attrs in job listing functions (#4762)
+ * shell: rlimit: improve handling of limits over hard limit (#4752)
+
+## Cleanup
+ * cleanup: remove some unused functions (#4806)
+ * job-manager: use allocation terms consistently (#4775)
+ * content: cleanup and minor tooling updates (#4770)
+
+## Testsuite/CI/Development
+ * testsuite: add flux job raise/cancel/kill tests (#4747)
+ * github: fix automated tag release action (#4755)
+ * Vscode setup (#4683)
+ * ci: revert to ubuntu-20.04 for workflow jobs that fail on ubuntu-latest
+ (#4794)
+ * testsuite: fix several corner cases in t0029-filemap-cmd (#4812)
+
+
+flux-core version 0.45.0 - 2022-11-01
+-------------------------------------
+
+## New Features
+ * propagate process resource limits to jobs (#4745)
+ * flux-job: support multiple jobids for `cancel`, `raise`, and `kill` (#4721)
+ * flux-resource: unify output format options, support config files and
+ named formats (#4710)
+ * broker: support binomial tree topology (#4730)
+ * broker: allow custom topology to be configured (#4675)
+ * flux-mini: add -x short option for --exclusive (#4726)
+ * flux-jobs: support emoji output formats (#4687)
+ * flux config: add load subcommand (#4695)
+ * broker: ignore ENOSYS from parent job-exec.critical-ranks RPC (#4680)
+ * job-list: support retrieving job's core count (#4664)
+ * job-list: add successful job count stat (#4739)
+ * job-list: support queue specific stats (#4684)
+ * etc: add functional bash completions (#4661, #4742)
+
+## Fixes
+ * job-list: ensure purged jobs are inactive (#4738)
+ * flux-proxy: require owner == proxy user (#4712, #4735)
+ * support mpi=none shell option and make it the default for `flux mini
+ batch` and `flux mini alloc` (#4731)
+ * unset job environment variables in initial program (#4717)
+ * flux-resource: fix scalability issues with large sets of resources (#4713)
+ * build: fix use of system bash-completion dir (#4667)
+ * rc1: reload configuration on rank > 0 (#4665)
+ * broker/test: Fix runat race on older glibc versions (#4660)
+ * broker: launch non-interactive shells in a new process group (#4653)
+
+## Cleanup
+ * job-list: cleanup error logging, remove excess logging (#4744)
+ * README: update flux help output (#4688)
+ * python: indicate truncation for some fields in flux-jobs and flux-resource
+ (#4670)
+ * python: move and rename some classes for reusability (#4669)
+ * job-list: refactor to abstract "idsync" logic better (#4644)
+ * broker: don't log failed `CONTROL_DISCONNECT` (#4656)
+
+## Testsuite/CI/Development
+ * fix github action syntax for output and yaml formatting (#4733)
+ * add devcontainer autocomplete (#4709)
+ * lint: update devcontainer to work with pre-commit (#4690)
+ * codeql: fix some critical issues found by security scanning (#4729)
+ * Create codeql.yml (#4705)
+ * ci: add isort to pre-commit and linting (#4691)
+ * ci: update setup-python/buildx actions to v4/v2 (#4693)
+ * Pre-commit extensions and multi-version setup (#4689)
+ * ci: consolidate python linting and formatting (#4636)
+ * Add devcontainer environment for vscode (#4674)
+ * test: job-ingest: skip guest tests when default sign-type fails (#4655)
+
+flux-core version 0.44.0 - 2022-10-04
+-------------------------------------
+
+This release includes initial support for job queues, which can be
+configured to partition resources with different limits and defaults.
+See `flux-config-queues(5)` for details.
+
+Other highlights include:
+
+ * Add ability to modify jobspec at the time of ingest with a new
+ job frobnicator framework similar to the existing validators.
+ * A new alternative to `system.R` for configuration of resources
+ (See `flux-config-resource(5)` for details)
+ * All child Flux instances are resilient to non-critical node failures
+ * Updates to `flux jobs` including better default output, a set of
+ new default named formats (See `flux jobs --format=help`), and support
+ for config files to add more named formats.
+
+## New Features
+ * ingest: set configured queue constraints (#4587)
+ * ingest: enable frobnicator when needed by [queues] or [policy] (#4608)
+ * reject jobs submitted to a named queue when none are configured (#4627)
+ * make queue state persist across instance restart (#4640)
+ * flux-mini: add `-q, --queue=NAME` option (#4599)
+ * flux-top: add minimal support for job queues (#4605)
+ * flux-jobs: support getting job queue and filtering by job queue (#4579)
+ * flux-jobs: support collapsible format fields (#4591)
+ * flux-jobs: add configurable named formats (#4595)
+ * flux-jobs: add queue to builtin format strings (#4607)
+ * flux-jobs: add `--format=long` (#4642)
+ * flux-jobs: support width and alignment with `!d` conversion specifier (#4597)
+ * python: add `contextual_time` jobinfo field (#4641)
+ * python: add `contextual_info` jobinfo field (#4626)
+ * broker: reduce `tbon.tcp_user_timeout` (#4632)
+ * make child instances resilient to non-critical node failures (#4615)
+ * resource: support configuration of resources in TOML config (#4566)
+ * drop environment from KVS jobspec (#4637)
+ * docker: add namespaced builds for spack/ubuntu (#4577)
+
+## Fixes
+ * flux-mini: change default unit for `--time-limit` to minutes (#4565)
+ * job-list: handle per-resource "cores" special cases (#4630)
+ * job-list: handle per-resource ntasks special case (#4555)
+ * job-list: use libjj to parse jobspec (#4611)
+ * job-list: parse tasks with total count in jobspec (#4651)
+ * job-info: return error on invalid eventlog append (#4624)
+ * flux-shell: always use `pmi=pershell` by default (#4621)
+ * ingest: require job queue if [queues] are configured (#4616)
+ * job-ingest: assign jobspec defaults before scheduler feasibility check
+ (#4529)
+ * configure: remove `--without-python` (#4584)
+ * configure: fix obsolete autotools warnings (#4588)
+ * configure.ac: fix error message when running autogen.sh (#4590)
+ * job-manager: print better errors on inactive move (#4586)
+ * broker: fix use-after-free segfault (#4570)
+ * python: uri: use path to current flux executable in lsf resolver (#4559)
+ * spack: add flux-core container build (#4561)
+ * improve signal/noise ratio in systemd journal logs (#4560)
+ * flux-mini: improve an error message and documentation for per-resource
+ options (#4549)
+ * doc: document `{id.dec}` in `flux-jobs(1)` (#4548)
+ * doc: add note about flux `--parent` option in `flux-mini(1)` (#4650)
+ * job-manager: do not ignore failure to load configured plugins (#4647)
+
+## Cleanup
+ * job-list: remove circular header dependencies (#4639)
+ * job-list: split out job information into new files (#4575)
+ * job-list: misc cleanup (#4563)
+ * Container base: remove view copy (#4551)
+
+## Testsuite
+ * testsuite: document `FLUX_TEST_VALGRIND` (#4643)
+ * testsuite: remove errant `test_done` call (#4609)
+ * testsuite: fix spurious resource norestrict test failures on some version
+ of hwloc (#4550)
+
+
+flux-core version 0.43.0 - 2022-09-06
+-------------------------------------
+
+This release includes changes after several weeks of Flux running as the
+primary resource manager on two small production systems at LLNL. Some
+noteworthy changes are: new options to flux-jobs(1) and flux-mini(1), show
+detailed job state in flux-jobs(1) output, and automatic KVS garbage
+collection. Also included: bug fixes for for cpu affinity, tcsh users,
+users with non-UTF-8 compliant terminals, and a rank 0 broker segfault when
+inactive job purging is enabled.
+
+## New Features
+ * cmd: add "per-resource" allocation options to flux-mini run and submit
+ (#4544)
+ * job-list: return nnodes if jobspec specifies nodes (#4542)
+ * resource: add norestrict option to avoid restricting hwloc topology XML
+ (#4538)
+ * flux-mini: add --bg option to flux-mini alloc (#4531)
+ * kvs: support gc-threshold config (#4528)
+ * etc: support content.backing-module=none (#4492)
+ * fetch J instead of jobspec in the job shell, support flux job info
+ --original jobspec (#4523)
+ * flux-jobs: add --since=WHEN and --name=NAME options (#4517)
+ * add flux jobtap query subcommand (#4507)
+ * libkvs: Support `KVS_CHECKPOINT_FLAG_CACHE_BYPASS` flag (#4477)
+ * flux-mini: --setattr: place keys in `attributes.system` by default
+ and default value to 1 (#4483)
+ * kvs: add root sequence number to checkpoint object (#4475)
+
+## Fixes
+ * shell: inherit `FLUX_F58_FORCE_ASCII` from job environment (#4541)
+ * shell: fix cpu-affinity=per-task (#4537)
+ * flux-mini: fix bulksubmit help message (#4539)
+ * fix ssh connector with csh/tcsh shells (#4532)
+ * broker: log content store errors to `LOG_CRIT` (#4526)
+ * broker: forward content.checkpoint-{get,put} RPCs to rank 0 (#4519)
+ * cmd/flux-jobs: include job state in status output (#4515)
+ * flux-jobs: improve bad username error message (#4503)
+ * update fluid check to check explicitly for utf-8 (#4505)
+ * doc: add TIMEOUT result to flux-jobs(1) (#4500)
+ * fix formatting issues with large UIDs (#4489)
+ * broker: fix content-cache flush list corruption (#4484)
+ * top: fix detailed report in summary pane (#4479)
+ * content-{sqlite,files,s3}: route checkpoint-get and checkpoint-put
+ through broker (#4463)
+ * job-list: avoid segfault after job purge (#4470)
+
+## Cleanup
+ * job-list: remove job-list.list-inactive RPC (#4513)
+ * flux-job: point users to flux-jobs(1) (#4499)
+ * docker: typo in path to Dockerfile (#4490)
+ * add start of spack base image for flux-core (#4471)
+ * docker: add pam development package to images (#4473)
+ * refactor broker overlay for topology flexibility (#4474)
+ * github: fixes for issues found when pushing a tag (#4462)
+
+## Testsuite
+ * testsuite: fix non-bourne shell test failure (#4543)
+ * testsuite: add more checkpoint sequence tests (#4518)
+ * testsuite: use flux jobs in valgrind workload (#4512)
+ * testsuite: unset `FLUX_F58_FORCE_ASCII` during testsuite (#4509)
+ * testsuite: add timeout job tests (#4501)
+ * testsuite: misc valgrind cleanup (#4480)
+
+
+flux-core version 0.42.0 - 2022-08-02
+-------------------------------------
+
+## New Features
+
+ * add flux_open_ex(3) (#4450)
+ * flux-top: support split of inactive jobs into completed and failed (#4449)
+ * job-manager: add limits plugins for duration and job size (#4415)
+ * kvs: add defensive checkpoint and kvs.checkpoint-period TOML config (#4383)
+ * python: add LSF URI resolver plugin (#4385)
+ * allow configurable defaults for jobspec system attributes (#4386)
+ * jobtap: add conf.update callback (#4411)
+ * Add a posix_spawn() implementation to libsubprocess and use it to launch
+ job shells (#4395)
+ * jobtap: add job.create, job.destroy callbacks (#4392)
+ * job-manager: allow dependencies on inactive jobs (#4388)
+
+## Fixes
+
+ * content-sqlite,files,s3: register with cache after setup complete (#4458)
+ * flux-overlay: add man page, open to guest users (#4459)
+ * flux-relay: initialize log prefix to hostname when possible (#4454)
+ * flux-top: avoid premature exit on recursive top error (#4452)
+ * job-manager: improve robustness of max job id recovery on restart (#4443)
+ * flux-config-bootstrap(5): improve hosts description (#4444)
+ * libflux: handle flux_respond_error (errnum=0) (#4427)
+ * flux-queue(1): add man page (#4426)
+ * sched-simple: fix allocation of down nodes when using constraints (#4425)
+ * job-archive: improve logging on parse job error (#4422)
+ * job-info: handle invalid eventlog entry errors more carefully (#4416)
+ * flux-dump: fix handling of empty blobref value (#4418)
+ * job-manager: fix race in job eventlog commit and job shell start (#4412)
+ * job-manager: fix dependency-add from job.state.depend callback (#4406)
+ * job-manager: ensure job aux items are destroyed safely (#4397)
+ * job-manager: fix restart code to handle jobs from earlier releases (#4399)
+
+## Cleanup
+
+ * use ccan ARRAY_SIZE() macro (#4445)
+ * kvs: rename kvs.sync target to kvs.wait-version (#4410)
+ * Use flux_error_t and errprintf() over char buf and snprintf() (#4407)
+ * content-sqlite: fix double free (#4391)
+ * kvs: misc cleanups (#4389)
+
+## Testsuite
+
+ * ci: create kvs dumpfile from previous tag for testing (#4402)
+
+flux-core version 0.41.0 - 2022-07-04
+-------------------------------------
+
+## New Features
+
+ * job-manager: transition NEW to DEPEND on "validate" event (#4366)
+ * kvs: support FLUX_KVS_SYNC (#4348)
+ * shell: obtain hwloc XML from enclosing instance (#4373)
+ * libkvs: add `flux_kvs_commit_get_rootref()` (#4374)
+
+## Fixes
+
+ * job-manager: fix case where a job manager epilog can't be configured
+ without a prolog (#4382)
+ * broker: return error in content.flush if no backing store exists (#4376)
+ * broker: content cache corner case corrections (#4380)
+ * job-manager: transition back to PRIORITY state on urgency update (#4364)
+ * wait for 'finish' instead of 'clean' event in flux-mini run and flux-job
+ attach (#4361)
+
+## Cleanup
+
+ * kvs: remove excess logging of ENOTSUP (#4381)
+ * job-manager: misc cleanup (#4362)
+
+## Testsuite
+
+ * testsuite: fix perilog sanity test (#4363)
+ * t2201-job-cmd.t: fix bug in UTF-8 test (#4360)
+
+flux-core version 0.40.0 - 2022-06-07
+-------------------------------------
+
+## New Features
+
+ * content-sqlite: verify database integrity during module load (#4340)
+ * job-exec: support new sdexec job launch plugin (#4070)
+ * job-manager: post submit event, instead of job-ingest (#4346)
+ * shell: execute job tasks in their own process group (#4355)
+
+## Fixes
+
+ * shell: improve handling of TMPDIR (#4330)
+ * job-manager: do not send purged events (#4334)
+ * job-list: consistently return job attributes (#4327)
+ * python: fix confusing error message from pid URI resolver (#4335)
+ * improve logging of overlay peer authentication (#4342)
+ * libflux: return better errno in future wait path (#4345)
+ * shell: fix reconnect hang (#4293)
+ * libsubprocess: avoid segfault on empty argv (#4350)
+ * docs: add python resource_list docstrings (#4353)
+
+## Cleanup
+
+ * job-list: misc cleanup (#4332)
+ * job-manager: misc cleanup (#4352)
+
+## Testsuite
+
+ * docker: update default version of flux-security to v0.7.0 (#4356)
+
+
+flux-core version 0.39.0 - 2022-05-06
+-------------------------------------
+
+## New Features
+
+ * job-list: support new "all" attribute to get all job attributes (#4324)
+ * flux-overlay: replace --no-color with --color=WHEN (#4322)
+ * flux-overlay: add -H, --highlight option (#4322)
+ * flux-shutdown: add --gc garbage collection option (#4303)
+ * content: track RFC 10 protocol changes (#4299)
+ * flux-dmesg: colorize output and add -H, --human option (#4289)
+ * job-manager: add inactive job purge capability (#4286)
+ * libutil: support "ms" suffix for Flux Standard Duration (#4284)
+ * add flux-resource info subcommand (#4272)
+
+## Fixes
+
+ * python: uri: fix intermittent failure of fallback pid resolver (#4320)
+ * flux-job: fix purge usage message (#4318)
+ * use correct type in content-sqlite, misc. content test cleanup (#4315)
+ * job-archive: use safer pragmas (#4307)
+ * select safer content.sqlite consistency pragmas (#4294)
+ * sched-simple: do not allocate down nodes with --exclusive (#4292)
+ * python: fix return from `flux.importer.import_plugins()` when no plugins
+ found (#4288)
+ * fix hang when job with an interactive pty fails early (#4283)
+ * broker: prevent downstream peers from connecting during shutdown (#4277)
+
+## Cleanup
+
+ * flux-shutdown(1): document new options (#4323)
+ * README: add libarchive prerequisite (#4319)
+ * content-s3: cosmetic cleanup (#4314)
+ * job-list: misc cleanups (#4297)
+ * broker: suppress online message with no members (#4298)
+ * job-manager: introduce config callback (#4279)
+ * libev: update to version 4.33 (#4282)
+ * libflux: convert `flux_conf_error_t` to `flux_error_t` (#4278)
+ * resource: stop collecting/reducing hwloc XML (#4263)
+ * flux-hwloc: remove command (#4262)
+ * flux-resource: remove ranks from default status output (#4271)
+ * libsubprocess: remove prefix on server setup (#4268)
+
+## Testsuite
+
+ * testsuite: increase test timeout (#4321)
+ * teststuite: document and fixup LONGTEST tests (#4305)
+ * testsuite: minor README fixes / updates (#4291)
+ * docker: update default flux-security version to v0.6.0 (#4274)
+ * testsuite: fix failing tests on parallel testsuite runs (#4275)
+ * ci: add build for Fedora 35 (#4270)
+
+flux-core version 0.38.0 - 2022-04-04
+-------------------------------------
+
+This release makes a few improvements that are visible in the flux-mini(1)
+command:
+
+ * The `-N,--nnodes` option may be used without the `-n,--nprocs` option.
+ * The `--exclusive` option requests the allocation of whole nodes.
+ * The `--requires` option requests resources with generic properties.
+
+Additionally, Flux system administrators should be aware of these changes:
+
+ * Named properties may be assigned to resources in the configured R.
+ * flux-shutdown(1) is now the preferred way to stop a Flux system instance.
+ * The default `archive.dbpath` is now `/var/lib/flux/job-archive.sqlite`.
+ * systemd-coredump(8) can now capture a Flux broker core dump. Consider
+ enabling this on the management nodes of early access systems to help
+ gather information on critical rank 0 broker failures, should they occur.
+ * `flux resource drain` now shows nodes as "draining" if they are still
+ running work.
+ * Flux may be configured to reject jobs that do not run in a Flux sub-instance.
+
+For more information, see the Flux Administrator's Guide:
+
+https://flux-framework.readthedocs.io/en/latest/adminguide.html
+
+## New Features
+
+ * add flux-shutdown command (#4250)
+ * add flux-dump and flux-restore (#4208, #4225)
+ * support for node exclusive allocations (#4245)
+ * add support for resource properties (#4236)
+ * flux-resource: support properties when listing resources (#4249)
+ * job-ingest: add TOML config (#4238)
+ * flux-dmesg: add --new option, plus logging cleanup (#4237)
+ * add 'require-instance' job validator plugin (#4239)
+ * job-manager: add builtin job duration validator plugin (#4224)
+ * sched-simple: set expiration of jobs with no duration to instance lifetime
+ (#4223)
+ * flux-resource: differentiate drained vs draining ranks (#4205)
+ * librlist: support hwloc discovery of AMD RSMI GPUs (#4203)
+ * broker: reject remote exec requests on rank 0 (#4258)
+ * python: allow resource count of 0 in jobspec v1 (#4259)
+ * job-archive: use statedir path if dbpath is not set (#4260)
+
+## Fixes
+
+ * content-sqlite: ensure that module load fails if initialization fails (#4265)
+ * job-archive: use statedir path if dbpath not set (#4260)
+ * broker: emit error when running interactive shell without tty (#4253)
+ * broker: add statedir attribute, drop content.backing-path (#4248)
+ * broker: prevent systemd restart if rc1 fails (#4246)
+ * flux.service: use StateDirectory for content.sqlite (#4244)
+ * rc3: ensure exit code reflects any errors (#4243)
+ * broker: don't leave shutdown state prematurely (#4241)
+ * libjob: improve `flux_job_statetostr()`, `flux_job_resulttostr()`
+ interface (#4235)
+ * job-list: fix bugs in some error paths (#4233)
+ * broker: fine tune logging and enable core dump on SIGSEGV (#4231)
+ * kvs: always store empty directory object to content store (#4229)
+ * restrict access to content service used as KVS blob layer (#4216)
+ * content-sqlite: check that file has rw permission (#4215)
+ * broker: block SIGPIPE (#4211)
+ * shell: add hostname to a couple key log messages (#4200)
+ * python: add missing methods and improve efficiency of IDset class (#4209)
+ * systemd: set SyslogIdentifier to flux (#4206)
+ * misc minor fixes and cleanup (#4197)
+ * job-exec: fix more potential hangs after early shell failure (#4199)
+ * sched-simple: fix counting bug that can cause scheduler to fail after
+ a restart (#4196)
+ * flux-top: add man page, minor bug fixes (#4194)
+
+## Cleanup
+
+ * broker: clean up shutdown logs (#4257)
+ * libsdprocess: minor fixups (#4252)
+ * job-manager: misc cleanup (#4232)
+
+## Testsuite
+
+ * testsuite: fix a couple intermittent test failures (#4247)
+ * ci: run 32bit build under linux32 personality (#4240)
+ * testsuite: ensure tests can run concurrently with `--root=$FLUX_JOB_TMPDIR`
+ (#4212)
+
+
+flux-core version 0.37.0 - 2022-03-04
+-------------------------------------
+
+This release disables resource verification of GPUs by default to
+workaround issues with GPU detection with system versions of hwloc.
+
+### Fixes
+
+ * resource: restrict resource verification to cores/hostnames only (#4192)
+ * resource: assign ranks in R based on hostlist attribute (#4188)
+ * add assertions that rank, size, hostlist broker attributes are cacheable
+ (#4187)
+
+### Testsuite
+
+ * testsuite: fix racy tests in t0005-rexec (#4179)
+
+### Cleanup
+
+ * build: ensure autogen.sh updates package version (#4174)
+
+
+flux-core version 0.36.0 - 2022-03-01
+-------------------------------------
+
+This release adds support for restarting a Flux system instance in safe
+mode after a failure to shut down properly -- for example in the case of a
+broker crash. New `flux-startlog(1)` and `flux-uptime(1)` commands are
+also introduced to give a quick review of the start and stop times and
+status of the current Flux instance.
+
+System instance users will want to update their configuration files to
+set `tbon.tcp_user_timeout` and remove `tbon.keepalive_*`, if present.
+For more information, see the Flux Admin Guide:
+
+https://flux-framework.readthedocs.io/en/latest/adminguide.html
+
+### Fixes
+
+ * job-exec: fix job hang after early IMP/shell exit (#4155)
+ * broker: allow `tbon.zmqdebug` to be set in config file and make sure it's
+ really off if set to 0 (#4127)
+ * broker: handle network partition (#4130)
+ * shell: capture job shell error messages in designated output file (#4125)
+ * resource: emit a more specific error when `rlist_rerank()` fails (#4126)
+ * flux-overlay: fix timeout error message (#4131)
+ * README: add libc development packages in requirements (#4133)
+ * libflux/future: set missing errno in `flux_future_wait_for()` (#4162)
+ * flux-config-archive(5): fix TOML example (#4164)
+ * shell: fix delay in completion of jobs with a single shell rank (#4159)
+
+### New Features
+
+ * flux-uptime: provide useful output for slow/stuck broker state (#4172)
+ * improve KVS checkpoint protocol to allow for future changes (#4149)
+ * add `flux config get` (#4166)
+ * broker: use RPC not control message for broker module sync/status (#4110)
+ * docs: add Python overview documentation (#4104)
+ * Support new libsdprocess to launch processes under systemd (#3864)
+ * rename keepalive messages to control messages (#4112)
+ * resource: enhance resource.drain RPC with "update" and "overwrite" modes
+ (#4121)
+ * broker: replace keepalive tunables with `tcp_user_timeout` (#4118)
+ * kvs: add date to kvs-primary checkpoint (#4136)
+ * libpmi2: implement bits needed for Cray MPI (#4142)
+ * add `flux-uptime` command (#4148)
+ * add `flux-startlog` and enter safe mode after crash (#4153)
+ * libflux: add `flux_hostmap_lookup(3)` (#4157)
+
+### Cleanup
+
+ * drop unused project meta files (#4170)
+ * doc: update flux-broker-attributes(7) (#4119)
+ * python: return `JobID` from flux.job.submit, not `int` (#4134)
+ * consolidate multiple `*_error_t` structures into a common `flux_error_t`
+ (#4165)
+ * drop unused project meta files (#4170)
+
+### Testsuite
+
+ * testsuite: remove unportable cshism (#4115)
+ * codecov: minor improvements for coverage reporting (#4147)
+ * testsuite: add clarification comments (#4167)
+
+
+flux-core version 0.35.0 - 2022-02-05
+-------------------------------------
+
+This release fixes a broker crash when a job receives an exception after
+running a job prolog. Users of the prolog/epilog feature should update
+to this version as soon as possible.
+
+In addition, TCP keepalive support was added for detection of powered off
+compute nodes. For configuration info, see the Flux Admin Guide:
+
+https://flux-framework.readthedocs.io/en/latest/adminguide.html
+
+
+### Fixes
+
+ * flux-ping: support hostnames in TARGET #4105
+ * Fix broker segfault when an exception is raised on a job after prolog (#4096)
+ * flux-overlay: improve timeouts, hostname handling (#4095)
+ * flux resource: allow limited guest access (#4094)
+ * shell: fix duplicate logging after evlog plugin is initialized (#4085)
+ * shell: do not allow instance owner to use guest shell services (#4101)
+ * shell: fix race in attach to interactive job pty (#4102)
+ * libterminus: fix leak in pty client code (#4098)
+
+### New Features
+
+ * broker: use TCP keepalives (#4099)
+ * systemd: set restart=always (#4100)
+ * flux-mini: add --wait-event option to submit/bulksubmit (#4078)
+
+### Testsuite
+
+ * testsuite: fix spellcheck (#4082)
+ * ci: rename centos images to el, and use rockylinux for el8 image (#4080)
+
+
+flux-core version 0.34.0 - 2022-01-28
+-------------------------------------
+
+This release features the automatic draining of "torpid" (unresponsive)
+nodes, to prevent new work from being scheduled on them until the instance
+owner investigates and runs `flux resource undrain`.
+
+### Fixes
+
+ * libsubprocess: fix excess logging and logging corner cases (#4060)
+ * doc: fix cross-references (#4063)
+ * flux-proxy: improve experience when proxied Flux instance terminates
+ (#4058)
+ * flux-perilog-run: improve usefulness of logging when prolog/epilog fails
+ (#4054)
+ * Fix issues found on Cray Shasta (perlmutter) (#4050)
+ * env: fix prepend of colon-separated paths in reverse order (#4045)
+ * python: fix ImportError for collections.abc.Mapping (#4042)
+ * job-list: fix "duplicate event" errors (#4043)
+ * systemd: set linger on flux user (#4035)
+
+### New Features
+
+ * shell: enhance pty support (#4075)
+ * add broker.starttime; add uptime to flux-top, flux-pstree (#4076)
+ * libflux: add `flux_reconnect()`, revamp flux fatal error callback (#4016)
+ * doc: add/improve man pages for config files (#4057, #4069)
+ * resource: drain torpid nodes (#4052)
+
+### Cleanup
+
+ * broker/content: misc cleanup (#4074)
+ * improve error message from flux-proxy and flux-jobs for invalid and
+ unknown jobids (#4062)
+ * cmd/flux-ping: make help output clearer (#4061)
+ * configure: Add python docutils check, do not require doc utils to build
+ flux help (#4056)
+
+### Test
+
+ * testsuite: fix non-bourne shell test failure (#4064)
+ * sharness: unset `FLUX_CONF_DIR` for all tests (#4059)
+ * ci: fix use of poison-libflux.sh and add poison `flux-*` commands (#4046)
+
+
+flux-core version 0.33.0 - 2022-01-08
+-------------------------------------
+
+This release includes several improvements in the recursive tooling
+in Flux to enhance the user experience when dealing with nested jobs.
+
+Highlights include:
+
+ * Improved interface for job URI discovery allows `flux proxy` and
+ `flux top` to target jobids directly.
+ * Addition of a `-R, --recursive` option to `flux jobs`
+ * Support in `flux top` for selecting and recursing into sub-instances
+ * A new `flux pstree` command for displaying job hierarchies in a tree
+
+### Fixes
+
+ * systemd: fix typo in flux.service unit file (#3996)
+ * libflux: check reactor flags (#4014)
+ * fix uninterruptible hang when attached to terminated jobs with -o pty
+ (#4010)
+ * cmd/flux-jobs: re-work -A option and clarify -a option (#4012)
+ * broker: avoid inappropriate quorum.timeout (#4027)
+ * add workaround for invalid job timeouts when system is busy (#4037)
+
+### New Features
+
+ * add FluxURIResolver Python class and flux-uri command for job URI
+ discovery (#3999)
+ * cmd: support high-level URIs and JOBID arguments in flux-top and
+ flux-proxy (#4004, #4015)
+ * flux-top: allow top to recursively call itself (#4011)
+ * flux-jobs: add --recursive option (#4019, #4024)
+ * flux-jobs: support instance-specific fields in output (#4022)
+ * add flux-pstree command (#4026)
+
+### Cleanup
+
+ * doc: add flux-resource(1), clean up help output (#4021)
+ * doc: audit / cleanup SEE ALSO and RESOURCES, add cross references (#4007)
+ * doc: misc updates and fixes (#4009)
+ * connector cleanup (#4013)
+ * connectors: avoid embedded synchronous RPC for subscribe/unsubscribe
+ (#3997)
+
+### Test
+
+ * testsuite: minor testsuite fixes (#4023)
+ * ci: add ability to run tests under system instance (#3844)
+ * fluxorama: allow user to sudo to flux user, add common systemd environment
+ vars to flux user's bashrc (#4031)
+
+
+flux-core version 0.32.0 - 2021-12-05
+-------------------------------------
+
+This release adds early groundwork for recovering running jobs across a
+Flux restart. It also includes improved log messages based on user feedback
+about Flux failures on real workflow runs, a first draft of a new `flux top`
+tool, and a critical fix for system deployments of Flux (#3958).
+
+### Fixes
+
+ * python: fix reference counting for Python Message objects (#3983)
+ * python: avoid early garbage collection of Watcher objects (#3975)
+ * libflux: improve safety against refcounting bugs in message functions (#3985)
+ * shell: reject PMI clients that request v2 (#3953)
+ * resource: don't abort if topo-reduce is received more than once (#3958)
+
+### New Features
+
+ * systemd: start flux systemd user service (#3872)
+ * broker: record child instance URIs as job memo (#3986)
+ * Support job memo events (#3984)
+ * job-exec: checkpoint/restore KVS namespaces of running jobs (#3947)
+ * set hostlist broker attribute when bootstrapped by PMI (#3966)
+ * add `flux_get_hostbyrank()` and improve broker attribute caching (#3971)
+ * broker: log slow nodes during startup (#3980)
+ * add flux-top command (#3979)
+
+### Cleanup
+
+ * flux-overlay: improve default status output, rework options (#3974)
+ * job-exec: improve job exception message/logging on broker disconnect (#3962)
+ * drop flux-jobspec command (#3951)
+ * improve flux-mini bulksubmit --dry-run output with --cc (#3956)
+ * README: update LLNL-CODE (#3954)
+ * broker/overlay: misc cleanup (#3948)
+ * bring README.md up to date (#3990)
+ * docker: fix and update ci dockerfiles (#3991)
+
+### Test
+
+ * testsuite: sanitize environment, fix hang in t2607-job-shell-input.t (#3968)
+
+flux-core version 0.31.0 - 2021-11-05
+-------------------------------------
+
+This release includes two noteworthy system instance improvements:
+crashed/offline nodes now marked offline for scheduling, and support
+has been added for prolog/epilog scripts that run as root.
+
+For prolog/epilog setup info, see the Flux Admin Guide:
+
+https://flux-framework.readthedocs.io/en/latest/adminguide.html
+
+### Fixes
+ * build: allow python 3.10.0 to satisfy version check (#3939)
+ * resource: avoid scheduling on nodes that have crashed (#3930)
+ * broker: fail gracefully when rundir or local-uri exceed `AF_UNIX` path
+ limits (#3932)
+ * broker: ignore missing ldconfig when searching for libpmi.so (#3926)
+ * job-manager: fix running job count underflow and use-after-free when an
+ event is emitted in CLEANUP state (#3922)
+ * fix problems building flux when 0MQ is not installed as a system package
+ (#3917)
+ * python: do not auto-stop ProgressBar by default (#3914)
+
+### New Features
+ * support job prolog/epilog commands (#3934)
+ * job-manager: add prolog/epilog support for jobtap plugins (#3924)
+ * libidset: add high level set functions (#3915)
+ * kvs: optionally initialize namespace to a root reference (#3941)
+ * rc: load job-archive module in default rc (#3942)
+
+### Cleanup
+ * improve broker overlay logging and debugging capability (#3913)
+ * man: Add note about shell quoting/escaping (#3918)
+
+### Test
+ * mergify: set queue method to merge, not rebase (#3916)
+ * mergify: replace strict merge with queue+rebase (#3907)
+ * testsuite: fix non-bourne shell test failure (#3937)
+
+flux-core version 0.30.0 - 2021-10-06
+-------------------------------------
+
+### Fixes
+
+ * job-manager: small fixes for the alloc-bypass plugin (#3889)
+ * job-manager: release after:JOBID dependencies after "start" instead of
+ "alloc" event (#3865)
+ * shell: avoid dropping stderr after a PMI abort (#3898)
+ * shell: require `FLUX_SHELL_PLUGIN_NAME` in plugins to fix logging component
+ discovery (#3879)
+ * libflux: deactivate RPC message handlers after final response (#3853)
+ * remove duplicate directories from `FLUX_RC_EXTRA`, `FLUX_SHELL_RC_PATH`
+ (#3878)
+ * t: fix incorrect method call in test-terminal.perl (#3888)
+ * Fix a couple build and test issues on ppc64le with clang 6.0+ (#3875)
+
+### New Features
+
+ * jobtap: allow jobtap plugins to query posted events for jobs (#3863)
+ * jobtap: allow jobtap plugins to subscribe to job events (#3861)
+ * job-exec: enable manual override option for mock execution jobs (#3868)
+ * shell: improve initrc extensibility, support version specific mpi plugin
+ loading (#3890)
+ * shell: fixes and enhancements for plugin loading (#3859)
+ * shell: allow default rc path to be extended via `FLUX_SHELL_RC_PATH` (#3869)
+ * shell: add taskids idset to `flux_shell_get_rank_info(3)` (#3873)
+ * shell: add library of Lua convenience functions for use in plugins (#3856)
+ * resource: fail get-xml request on quorum subset (#3885)
+
+### Cleanup
+
+ * libflux/future: fix comment typo (#3860)
+ * NEWS.md: Fix typo for v0.29.0 (#3857)
+
+### Testsuite
+
+ * docker: add --build-arg to docker-run-checks, systemd-devel to centos8
+ (#3871)
+ * ci: add fedora 34 build and fix compiler errors from gcc 11.2 (#3854)
+
+
+flux-core version 0.29.0 - 2021-09-03
+-------------------------------------
+
+This release of Flux includes a new fault mechanism which ensures that
+unanswered RPCs receive error responses when the overlay network is
+disrupted. Also included is a new `flux overlay` utility which can be
+used to manage and report the status of the overlay network.
+
+### Fixes
+ * shell: fix in-tree pluginpath, add `shell_plugindir` (#3841)
+ * python: fix bug in FluxExecutor.attach method (#3839)
+ * rlist: fix erroneous collapse of nodes with different resource children
+ when emitting R (#3814)
+ * libkvs: compact only if ops len > 1 (#3807)
+ * python: allow executor to attach to jobs (#3790)
+ * python: fix version requirement in jobspec validator plugin (#3784)
+ * broker: ensure subtree restart upon loss of router node (#3845)
+ * broker: drop -k-ary option, rename tbon.arity attr to tbon.fanout (#3796)
+ * add flux-job(1) manual page, plus minor fixes (#3763)
+ * libjob: improve method for determining instance owner (#3761)
+
+### New Features
+ * add flux overlay status command (#3816)
+ * broker: improve logging of 0MQ socket events (#3846)
+ * broker: fail pending RPCs when TBON parent goes down (#3843)
+ * broker: fail pending RPCs when TBON child goes down (#3822)
+ * add `bootstrap.ipv6_enable = true` config option (#3827)
+ * shell: add functions to access jobspec summary information (#3835)
+ * add stats api for internal metric collection (#3806, #3824)
+ * support io encode/decode of binary data (#3778)
+ * add flag to bypass jobspec validation (#3766)
+ * libflux: add time stamp to message trace (#3765)
+
+### Cleanup
+ * libzmqutil: generalize the zeromq authentication protocol server (#3847)
+ * libflux: use iovec-like array over zmsg (#3773)
+ * libflux: update flux msg route functions (#3746)
+ * libflux: message API fixes and cleanup (#3771)
+ * libjob: break up job.c (#3768)
+ * build: consistently use CFLAGS / LIBS in Makefiles (#3785)
+ * use CCAN base64 library over libsodium base64 library (#3789)
+ * drop unnecessary 0MQ includes (#3782)
+ * various other cleanup (#3762)
+
+### Testsuite
+ * update to flux-security v0.5.0 in docker images (#3849)
+ * make valgrind test opt-in (#3840)
+ * add valgrind suppression for opencl and libev on aarch64 (#3794, #3809)
+
+flux-core version 0.28.0 - 2021-06-30
+-------------------------------------
+
+This release adds simple job dependencies - see the `flux_mini(1)`
+DEPENDENCIES section.
+
+### Fixes
+ * shell: fix segfault when more slots are allocated than requested (#3749)
+ * testsuite: avoid long `ipc://` paths in system test personality (#3739)
+ * cron: fix race in task timeouts (#3728)
+ * Python/FluxExecutor bug fixes (#3714)
+ * flux-python: fix use of virtualenv python (#3713)
+ * optparse: make `optional_argument` apply to long options only (#3706)
+ * librlist: skip loading hwloc 'gl' plugin (#3693)
+
+### New Features
+ * allow jobs to bypass scheduler with alloc-bypass jobtap plugin (#3740)
+ * libjob: add a library for constructing V1 jobspecs (#3662, #3734, #3748)
+ * python: validate dependencies in Jobspec constructor (#3727)
+ * libflux: make `flux_plugin_handler` topic member const (#3720)
+ * job-manager: add builtin begin-time dependency plugin (#3704)
+ * broker: send offline responses while broker is initializing (#3712)
+ * python: add `flux.util.parse_datetime` (#3711)
+ * job-manager: support simple `after*` job dependencies (#3696)
+ * jobtap: fixes and api enhancements to support dependency plugins (#3698)
+ * shell: add exit-on-error option (#3692)
+
+### Cleanup/Testing/Build System
+ * job-manager: minor cleanup and improvements for event handling (#3759)
+ * libflux: make `flux_msg_fprint()` output clearer (#3742)
+ * libflux: store fully decoded message in `flux_msg_t` (#3701, #3758)
+ * libflux: msg API cleanup, test cleanup, and test enhancement (#3745, #3699)
+ * testsuite: generalize valgrind suppressions (#3743)
+ * ci: use long path for builddir in test build (#3738)
+ * job-list: cleanup & testsuite modernization & consistency updates (#3733)
+ * testsuite: fix several tests on slower systems (#3730)
+ * testsuite: fix intermittent test, speed up others (#3725)
+ * broker: misc cleanup (#3721)
+ * github: fix ci builds on master (#3716, #3717)
+ * testsuite: add tests for late joining broker (#3709)
+ * flux-start: build system instance test features (#3700)
+ * ci: minor coverage testing fixes (#3703)
+ * libflux: test: fix segfault of `test_plugin.t` under rpmbuild (#3695)
+
+flux-core version 0.27.0 - 2021-05-28
+-------------------------------------
+
+This release features additional performance improvements that affect
+job throughput over time (see issue #3583).
+
+### Fixes
+ * shell/pmi: always populate `PMI_process_mapping` to avoid mvapich2
+ `MPI_Init` invalid tag error (#3673)
+ * openmpi: ensure that shmem segments for co-located jobs don't conflict
+ (#3672)
+ * python: fix FluxExecutorFuture cancellation bug (#3655)
+ * job-info, kvs-watch: support guest disconnect & credential checks (#3627)
+ * libflux: plugin: make `FLUX_PLUGIN_ARG_UPDATE` the default (#3685)
+
+### Performance
+ * kvs: reduce cache expiration overhead (#3664)
+ * kvs: remove client disconnect bottleneck (#3663)
+ * kvs: use json object to find duplicate keys (#3658)
+ * kvs: improve performance of transaction prep/check (#3654)
+ * content-cache: avoid linear search for dirty blobs (#3639)
+ * content-cache: make LRU purge more effective (#3632)
+ * flux-shell: add minor optimizations for single node jobs (#3626)
+ * libczmqcontainers: include zlistx, zhash, zlist, and convert internal
+ users (#3620)
+
+### New Features
+ * shell: add plugin to detect first task exit (#3681)
+ * job-manager: multiple jobtap plugin enhancements (#3687)
+ * job-manager: support a list of loaded jobtap plugins (#3667)
+ * shell: add tmpdir plugin to manage `FLUX_JOB_TMPDIR` (#3661)
+ * jobtap: support for `job.dependency.*` callbacks (#3660)
+ * flux-mini: avoid substitution without --cc/bcc, allow --setattr value
+ to be read from file (#3659)
+ * flux-start: add embedded server (#3650)
+ * flux-proxy: add flux-core version check (#3653)
+ * libflux: `msg_handler`: capture duplicate non-glob request handlers in a
+ stack (#3616)
+
+### Cleanup/Testing/Build System
+ * testsuite: add mvapich2 to centos8 CI image (#3686)
+ * testsuite: improve in-tree MPI testing (#3678)
+ * libflux: `flux_modfind`: ignore DSOs with no `mod_name` symbol (#3675)
+ * kvs: misc cleanup (#3671)
+ * flux-start: rename `--scratchdir` to `--rundir` (#3670)
+ * shell: misc environment-related fixes (#3669)
+ * testsuite: modify jobid capture logic (#3657)
+ * testsuite: handle hwloc issues and improve config file bootstrap test
+ (#3648)
+ * build: add and use autoconf variable for Flux plugin LDFLAGS (#3647)
+ * libutil: replace hand written hex conversion code with libccan (#3646)
+ * github: fixes for auto-release deployment (#3638)
+ * content-cache: general cleanup, small bug fixes, and test improvement
+ (#3645)
+ * kvs: add errmsg on namespace create failure (#3644)
+ * Use internal functions instead of zfile / zdigest (#3634)
+ * libutil: avoid `zmq_strerror()` (#3628)
+ * ci/test: switch to bulksubmit for inception tests, add throughput test,
+ dismiss reviews after PR updates (#3621)
+ * expand broker internal documentation to cover bootstrap phase (#3618)
+
+flux-core version 0.26.0 - 2021-04-22
+-------------------------------------
+
+This release features several performance improvements that affect
+job throughput over time (see issue #3583).
+
+### Fixes
+
+ * avoid mvapich segfault under flux start singleton (#3603)
+ * python: avoid throwing 2nd exception on unknown errno (#3588)
+ * avoid routing stale responses to restarted brokers (#3601)
+
+### Performance
+
+ * fix aggressive zhashx resize by importing fixed source (#3596, #3598)
+ * use zhashx, LRU in content-cache (#3589, #3593)
+ * drop root directory object from KVS setroot event (#3581)
+ * add minor optimizations to aux container (#3586)
+ * drop extra code in `flux_matchtag_free()` (#3590)
+ * libkvs: save KVS copy/move aux data in future not handle (#3585)
+
+### New Features
+
+ * libjob: add `flux_job_result(3)` (#3582)
+ * python: add explicit `service_(un)register` method (#3602)
+ * add overlay network version/config check (#3597)
+ * job-manager: enable job dependency management (#3563)
+
+### Cleanup/Testing
+
+ * flux-start: rename --size to --test-size, drop --bootstrap (#3605)
+
+flux-core version 0.25.0 - 2021-04-01
+-------------------------------------
+
+### Fixes
+
+ * kvs: fix assert due to busy KVS (#3560)
+ * systemd: configure weak dependency on munge (#3577)
+ * Fix various memleaks discovered by ASAN (#3568)
+ * README: add missing dependency - pkgconfig (#3570)
+ * fix `PMI_process_mapping` for multiple brokers per node (#3553)
+ * Python: fix "no such file or directory" job exception resulting from
+ bad jobspec (#3534)
+
+### New Features
+
+ * libflux: add `flux_plugin_aux_delete()` (#3565)
+ * job-info: support LRU cache mapping job id -> owner (#3548)
+ * python: expand FluxExecutor.submit parameters (#3562)
+ * broker: add support for PMIx bootstrap (#3537)
+ * job-ingest: add new plugin-based job validator (#3533)
+
+### Cleanup/Testing
+
+ * README.md: remove python3-six dependency (#3579)
+ * clean up disconnect, cancel handlers (#3569)
+ * broker: drop broker.rundir, select ipc vs tcp using broker.mapping (#3554)
+ * broker: refactor overlay network send/receive interfaces (#3547)
+ * github: add a stale issues and PR bot for flux-core (#3544)
+ * build/test: remove stale heartbeat references (#3535)
+ * job-info: consolidate watch RPC targets (#3525)
+ * enhance testsuite reliability on RHEL8/TOSS4 (#3540)
+
+
+flux-core version 0.24.0 - 2021-02-22
+-------------------------------------
+
+This release features multiple performance enhancements, including the
+addition of the FluxExecutor Python class which allows rapid, asynchronous
+submission of jobs.
+
+### Fixes
+
+ * broker: fix segfault/perf issues when hitting file descriptor limit (#3513)
+ * module: reduce keepalive message traffic (#3516)
+ * flux-kvs: fix --help output when not in an instance (#3500)
+ * flux-kvs: fix help output in nested subcommands (#3497)
+ * flux-mini: fix --progress counters with job exceptions (#3514)
+ * portability: fix 32-bit issues (#3507)
+ * portability: cross compilation fixes for Julia bindings (#3503)
+ * libflux: restart continuation timeout in `flux_future_reset()` (#3518)
+
+### New Features
+
+ * python: add concurrent.futures executor (#3468)
+ * libflux: add `flux_sync_create()` (#3524)
+ * job-manager: allow jobtap plugins to reject jobs (#3494)
+ * job-manager: support mode=limited (#3473)
+ * flux-mini: support `--urgency` values "default", "hold", "expedite" (#3499)
+ * broker: improve IP address heuristic in PMI bootstrap (#3489)
+ * flux-mini: add --log and --log-stderr options (#3509)
+ * use reactor time instead of heartbeats for internal time management (#3519)
+ * heartbeat: convert to loadable module (#3512)
+
+### Cleanup/Testing
+
+ * job-info: split into two modules, job-info and job-list (#3510)
+ * libflux: remove unnecessary `flux_future_then()` calls (#3520)
+ * testsuite: cleanup job-manager tests (#3488)
+ * testsuite: update hwloc-calc usage (#3523)
+ * ci: add fedora33 docker image for testing (#3498)
+ * ci: add 32 bit build to github ci checks (#3511)
+ * ci: explicitly checkout tag if creating a release (#3531)
+
+
+flux-core version 0.23.1 - 2021-01-27
+-------------------------------------
+
+### Fixes
+
+ * flux resource: allow drain, undrain, and status to work on any rank (#3486)
+ * job-manager: fix compilation error on gcc-10 (#3485)
+ * job-manager: fix uninitialized variable warning in jobtap.c (#3481)
+
+flux-core version 0.23.0 - 2021-01-25
+-------------------------------------
+
+This release adds a job priority plugin framework, enabling the
+flux-accounting project to set job priorities with a fair share
+algorithm.
+
+The scheduler protocol (RFC 27) and libschedutil convenience API
+have changed, therefore users of flux-sched must upgrade to 0.15.0.
+
+### New features
+
+ * jobtap: prototype job-manager plugin support (#3464)
+ * flux-mini: add bulk job submission capabilities (#3426, #3478)
+ * job-manager: send updated priorities to schedulers (#3442)
+ * job-manager: support job hold and expedite (#3428)
+
+### Fixes
+
+ * connectors/ssh: forward `LD_LIBRARY_PATH` over ssh when set (#3458)
+ * python: fix use of `Flux.reactor_run()` from multiple threads (#3471)
+ * python: misc. fixes to docstrings and argument names in bindings (#3451)
+ * python: fix circular reference in `check_future_error` decorator (#3437)
+ * python: fix ctrl-c, re-throw unhandled exceptions in `reactor_run()` (#3435)
+ * shell: fix dropped stdout from shell plugins in task.exec callback (#3446)
+
+### Cleanup/Testing
+
+ * ci: limit asan build to unit tests only (#3479)
+ * libschedutil: API improvements and priority integration (#3447)
+ * configure: add switch to allow flux to be built without python (#3459)
+ * testsuite: remove sched-dummy, migrate testing to sched-simple (#3462)
+ * testsuite: add debug, workarounds for failures in github actions (#3467)
+ * test: fix test for installing poison libflux (#3461)
+ * cleanup: update outdated terminology (#3456)
+ * Globally standardize spelling of "canceled" (#3443)
+ * ci: better script portability and other small updates (#3438)
+ * testsuite: fix invalid tests, cleanup list-jobs, avoid hard-coding (#3436)
+ * fix github actions on tag push (#3430)
+
+flux-core version 0.22.0 - 2020-12-16
+-------------------------------------
+
+This release resolves an issue introduced in 0.20.0 where Flux would
+occasionally hang during tear-down on RHEL/CentOS 7. This release
+should be suitable for use with production workflows on those systems.
+
+System instance development and testing at < 256 node scale is on-going.
+The system limitations of this release are documented in the Flux Admin
+Guide:
+
+https://flux-framework.readthedocs.io/en/latest/adminguide.html
+
+### New features
+
+ * flux-keygen is no longer necessary before starting Flux (#3409)
+ * Add waitstatus and returncode JobID class and flux-jobs (#3414)
+ * New `flux resource status` command (#3351)
+ * Rename "administrative priority" to "urgency" (#3394)
+ * Prepare for fair share priority plugin (#3371, #3339, #3350, #3402,
+ #3405, #3404, #3410)
+ * job-manager: cache jobspec for scheduler, exec (#3393, #3396, #3399)
+ * python: add bindings for libflux-idset,hostlist (#3341)
+ * resource: support hostnames for drain and exclude (#3318)
+ * flux-jobs: Support nodelist in flux-jobs output (#3332)
+ * flux-jobs: add flux-jobs --stats,--stats-only options (#3419)
+ * flux-job: Add flux job attach --read-only option (#3320)
+ * python: add ResourceSet python class (#3406)
+ * python: allow future.then() variable and keyword args in callbacks (#3366)
+
+### Fixes
+
+ * Fix job shell segfault when jobspec contains JSON null (#3421)
+ * job-manager: Fix annotation clear corner case #3418
+ * broker: fix intermittent hang during instance tear-down on Centos7 (#3398)
+ * job-exec: log early shell/imp errors (#3397)
+ * shell: ensure TMPDIR exists for all jobs (#3389)
+ * misc cleanups & fixups (#3392)
+ * small fixes: resource memory leak, improve errors, check int size (#3388)
+ * affinity: use comma separated list format for `CUDA_VISIBLE_DEVICES` (#3376)
+ * libjob: repair interoperability with flux-security (#3356)
+ * job-exec: fixes for multiuser mode (#3353)
+ * shell: fix issues with `CUDA_VISIBLE_DEVICES` value (#3317)
+ * job-manager: handle scheduler disconnect (#3304)
+ * libjob: always sign owner jobs with the 'none' signing mechanism (#3306)
+ * libsubprocess: do not allow ref/unref in hooks (#3303)
+
+### Cleanup/Testing
+
+ * doc: autogenerate python binding docs with Sphinx (#3412)
+ * testsuite: support level N inception of flux testsuite (#3413)
+ * github: fix missing docker tag in matrix builds (#3387)
+ * github: fixes for workflow scripts (#3383)
+ * ci: move from Travis-CI to GitHub Workflows (#3379)
+ * docs: add explicit link to man pages section (#3365)
+ * testsuite: replace loop in t2300-sched-simple.t with helper (#3367)
+ * docker: install poison flux-core libs, cmds before build and test (#3369)
+ * libflux: drop `flux_dmesg()` from public API (#3362)
+ * testsuite: fix shed-simple test races (#3358)
+ * build: allow Lua 5.4, drop -lutil, and improve sphinx warning (#3357)
+ * testsuite: increase resource.monitor-waitup timeout (#3348)
+ * broker: update log.dmesg to use rpc streaming (#3307)
+ * testsuite: fix core idsets in resource module tests (#3314)
+ * t/t2205-hwloc-basic: only use lstopo-no-graphics (#3309)
+
+flux-core version 0.21.0 - 2020-11-04
+-------------------------------------
+
+This release enables resources to be configured in advance when Flux is
+the native resource manager for a cluster, in lieu of dynamic discovery.
+For details, refer to the Flux Admin Guide:
+
+https://flux-framework.readthedocs.io/en/latest/adminguide.html
+
+### New features
+
+ * optparse: don't sort options/subcommands by default (#3298)
+ * flux-job: Output key options for job info (#3210)
+ * resource: load resources from config or R, and rework topo discovery (#3265)
+ * add internal librlist library and flux-R utility for R version 1 (#3276)
+ * job-info: use job manager journal to track job state (#3254)
+ * job-manager: support events journal (#3261)
+ * shell: support stdio buffering options (default stderr: unbuffered) (#3272)
+ * flux-kvs: Add 'flux kvs eventlog wait-event' subcommand (#3200)
+ * job-manager: send job annotations to journal instead of publishing (#3236)
+ * add hostlist library for encoding/decoding RFC29 hostlists (#3247)
+
+### Fixes
+
+ * broker: convert broker [bootstrap] config to use libhostlist (#3283)
+ * libflux: Add missing C++ header guards (#3280)
+ * cmd: display jobid with flux-mini alloc -v, --verbose (#3279)
+ * python: fix signal handler management in threads (#3266)
+ * rc1: fix local connector retries (#3301)
+
+### Cleanup
+
+ * remove flux-hwloc reload command and aggregator module (#3296)
+ * doc: add flux-jobs(1) examples (#3295)
+ * job-manager / job-info: misc cleanup (#3246)
+ * build: increase minimum version of jansson to 2.10 (#3240)
+ * ci: ensure pylint script fails when lint warnings are produced (#3269)
+
+
+flux-core version 0.20.0 - 2020-09-30
+-------------------------------------
+
+This release features changes to support Flux as the native resource
+manager on small (<= 256 node) clusters, for testing only. A draft system
+administration guide is available at:
+
+https://flux-framework.readthedocs.io/en/latest/adminguide.html
+
+### New features
+
+ * hwloc: add printing of num GPUs to `flux hwloc info` (#3217)
+ * resource: mark nodes down when they are stopped (#3207)
+ * broker: allow late-joining brokers, execute rc1/rc3 on all ranks (#3168)
+ * shell/pmi: add improved PMI key exchange mechanism (#3219)
+
+### Fixes
+
+ * job-manager: communicate job priority changes to job-info (#3208)
+ * job-info: handle annotations race (#3196)
+ * python/job: Update `state_single` default header (#3227)
+ * libidset: reject idset strings that don't conform to RFC 22 (#3237)
+ * job-info: handle job-priority changes (#3208)
+ * doc: list sphinx as a doc dependency in README.md (#3225)
+ * testsuite: fix race in python SIGINT test (#3224)
+ * job-manager: fix segfault changing priority of a running job (#3220)
+ * shell: allow multiple resources per level in jobspec (#3175)
+ * python: allow Ctrl-C interrupt of `Future.get()` and `wait_for()` (#3215)
+ * shell: use F58/alternate encodings in output file template {{id}} (#3206)
+ * fallback to ASCII for F58 FLUIDs with `FLUX_F58_FORCE_ASCII` (#3204)
+ * rc: load sched-simple only if no other scheduler is loaded (#3177)
+ * docker: do not install Sphinx via pip in Centos8 image (#3195)
+ * flux-jobs / python bindings: handle empty string conversions (#3183)
+
+### Cleanup
+
+ * reduce log noise (#3226)
+ * flux-comms: remove obsolete command (#3211)
+
+
+flux-core version 0.19.0 - 2020-08-31
+-------------------------------------
+
+Notable features and improvements in this release include enhanced
+support for tools/debuggers (e.g. STAT, LaunchMON and TotalView), a
+new set of `--env` environment manipulation options for flux-mini(1),
+better support for listing jobs through the Python API, and a fix
+for an annoying usability issue with F58 encoded jobids in non-UTF-8
+locales.
+
+
+### New features
+
+ * switch to utf-8 for subprocess and job io encoding (#3086)
+ * improve support for shell plugin developers (#3159, #3132)
+ * flux-mini: add environment manipulation options (#3150)
+ * flux-mini: add --debug option for tools support (#3130)
+ * bash: top level command completions for flux (#2755)
+ * add fluxorama system instance docker image sources (#3031, #3128)
+ * content-s3: add configuration, support for libs3 variants (#3067, #3115)
+ * Use F58 JOBIDs in most user-facing commands (#3111)
+ * broker: state machine refactoring (#3107)
+ * broker: restore client-side PMI logging (#3105)
+ * libflux: add `flux_module_set_running()` (#3104)
+ * python: Add JobInfo, JobInfoFormat, and JobList classes (#3174)
+
+### Fixes
+
+ * Fix F58 encoding in non-multibyte locales (#3144)
+ * job-info,job-shell: allow non-V1 jobspec (#3160)
+ * build: fix innocuous configure error (#3129)
+ * travis-ci: fix ARGS when `DOCKER_TAG` set (#3125)
+ * doc: fix flux-help(1) output and rendering of NODESET.rst (#3119)
+ * flux-job: add `totalview_jobid` support and misc. fixes (#3130)
+ * small build/test/doc fixes (#3100)
+ * fix GitHub project license detection (#3089)
+ * shell/lua.d/openmpi: set env vars to force the use of flux plugins (#3099)
+ * job-info: do not fail on invalid jobspec / R / eventlog (#3171)
+ * flux-module: extend first column of flux-module list output (#3178)
+
+### Cleanup
+
+ * python: split flux.job module into multiple files (#3162)
+ * python: reformat with latest black formatter, pin black version (#3169)
+ * libflux: fix comment in module.h to reference readthedocs (#3138)
+ * Update rfc links to RTD site (#3137)
+ * remove the simple dynamic string (sds) code from libutil (#3135)
+ * Doc Cleanup (#3117)
+ * AUTHORS: remove (#3090)
+
+flux-core version 0.18.0 - 2020-07-29
+-------------------------------------
+
+This release features a more compact default representation for Flux JOBIDs,
+manual pages converted to ReST format and published on
+[readthedocs.io](https://flux-framework.readthedocs.io/projects/flux-core/),
+and the ability for schedulers to add data to jobs which can be displayed
+with `flux jobs`.
+
+### New features
+
+ * doc: man pages converted to ReST for publication on readthedocs.io
+ (#3033, #3078, #3085)
+ * Add support for RFC19 F58 encoded JOBIDs (#3045)
+ * Support user and scheduler job annotations (#3065, #3062, #2960)
+ * add content-s3, content-files alternate backing stores (#3025, #2992)
+ * Python interface to 'mini batch' (#3020)
+
+### Fixes
+
+ * shell: fix bug in cpu-affinity=per-task (#3080)
+ * flux-hwloc: remove ignore of `HWLOC_OBJ_GROUP` (#3046)
+ * cmd: Make label io options consistent (#3068)
+ * flux-resource list: Allow null/missing key to designate empty set (#3047)
+ * flux-jobs: small functionality and testing updates (#3060)
+ * job-manager: avoid segfault on priority change with pending alloc (#3072)
+
+### Cleanup
+
+ * doc: adjust dependency table to reflect hwloc v2.0+ support (#3053)
+ * Update terminology to use more inclusive words (#3040)
+
+### Testsuite enhancements
+
+ * testsuite: remove use of -S option in `run_timeout` (#3079)
+ * testsuite: minor valgrind test cleanup (#3077)
+ * docker: small updates for testenv images, travis builds (#3058)
+ * travis-ci: add python coverage (#3056)
+ * travis-ci: Add `--localstatedir=/var` to docker tag builds (#3050)
+ * pylint: Update pylint to 2.4.4 (#3035)
+ * Fix testsuite for Lua 5.3 on Ubuntu 20.04 (#3028)
+ * docker: really actually fix Ubuntu 20.04 (focal) docker tags (#3027)
+ * travis-ci: enforce correct configure ARGS for docker tags (#3023)
+ * travis: tag a docker image for ubuntu 20.04 (#3022)
+ * python: add stdio properties to Jobspec class (#3019)
+ * build and test fixes (#3016)
+
+
+flux-core version 0.17.0 - 2020-06-18
+-------------------------------------
+
+*NOTE*: Support has been removed for Python 2.
+
+### New features
+
+ * Improved interface for batch jobs: `flux mini batch` and `flux mini alloc`
+ (#2962)
+ * Pty support for Flux jobs via `-o pty` shell option (#2894)
+ * New resource module for monitoring and control of resources,
+ including ability to exclude and drain/undrain ranks. (#2918, #2949)
+ * New `flux resource` utility to drain and list resources. (#2949)
+ * Multiple improvements for `flux jobs`: colorize output, add "status"
+ and "exception" fields, allow jobids as positional arguments, and
+ add a custom conversion type `h` for "-" (#2798, #2858, #2902, #2910,
+ #2940, #2926, #2865)
+ * Support for hwloc v2.0+ (#2944)
+ * Support for MPIR debugging of jobs (#2654)
+ * New job-archive module optionally stores job data in sqlite. (#2880)
+ * single-broker system instance support, including minimal
+ support for restart (archived job information is saved) (#2783, #2820,
+ #2813, #2809)
+ * Add support for multi-user execution (#2822, #2813)
+ * Add support for enforcing job time limits (#2995)
+ * python: Add bindings for job cancel and kill (#2976)
+ * python: Add bindings for watching job eventlog events (#2986)
+
+### Improvements
+
+ * support systemctl reload flux (#2879)
+ * enhance job throughput (#2777, #2792)
+ * sched-simple: schedule cores instead of PUs by default (#2966)
+ * broker: send service.disconnect requests on module unload (#2913)
+ * broker: add interface for monitoring broker liveness (#2914)
+ * broker: add cleanup phase (#2971)
+ * broker: only allow userid- services to be registered by guests (#2813)
+ * libflux: add `flux_msg_last_json_error(3)` (#2905)
+ * flux-job: Use common attrs for list cmds (#2901)
+ * doc: add flux job shell API manpages (#2793)
+ * job-info: Support "exception" and "success" list attributes (#2831, #2858)
+ * job-info: improve error responses from various list RPCs (#3010)
+ * rc: load job-info on rank 0 only (#3009)
+ * python: remove support for Python 2 (#2805)
+ * python: cache python wrappers in the class (#2878)
+ * python: tweaks in preparation for flux-tree-helper (#2804)
+ * python: add 'flux_job_list_inactive' Python binding (#2790)
+ * python: allow reactor_run() to be interrupted (#2974)
+ * config: parse TOML once in broker, share with modules (#2866)
+ * config: use config file for access policy (#2871)
+ * docker: add default PS1 that includes flux instance size, depth (#2925)
+ * docker: start munge in published docker images (#2922)
+
+### Fixes
+
+ * Fix compilation under GCC 10.1.0 (#2954)
+ * librouter: avoid dropping messages on EPIPE (#2934)
+ * README: update documentation link (#2929)
+ * README.md: fix required Lua version (#2923)
+ * README: add missing dependencies: aspell-en and make (#2889)
+ * shell: make registered services secure by default (#2877)
+ * cmd/flux-kvs: Fix segfault in dir -R (#2847)
+ * job-exec: drop use of broker attrs, use conf file or cmdline instead
+ (#2821)
+ * broker: clean shutdown on SIGTERM (#2794)
+ * flux-ping: fix problems with route string (#2811)
+ * libsubprocess: don't clobber errno in destructors, handle ENOMEM (#2808)
+ * Fix flux-job status for jobs with exceptions before start (#2784)
+ * shell: Add missing R member to shell info JSON object (#2989)
+ * job-ingest: fix validation of V1 jobspec (duration required) (#2994)
+ * doc: fixes and updates for idset manpages (#3012)
+
+### Cleanup
+
+ * removed outdated pymod module (#3008)
+ * broker and flux-comms cleanup (#2907)
+ * cmd/flux-kvs: Remove legacy --json options and json output (#2807)
+ * doc: Fix typos in man pages (#2725)
+ * libutil: improve out of memory handling, conform to RFC 7 (#2785)
+ * content-sqlite, content-cache: cleanup and refactoring (#2786)
+
+### Testsuite enhancements
+
+ * Fix skipped tests in t2205-hwloc-basic.t (#2998)
+ * t2204-job-info: Split up tests into new files (#2957)
+ * t/t2800-jobs-cmd: Fix racy test (#2951)
+ * t: add `HAVE_JQ` prereq to tests that use `jq` (#2936)
+ * sharness: fix TEST_CHECK_PREREQS for tests using $jq (#2939)
+ * job-info: module & test cleanup (#2932)
+ * testsuite: add ability to ensure programs are used under appropriate
+ prereqs (#2937)
+ * ensure unit tests do not link against installed flux libraries (#2917)
+ * t2204-job-info: Fix racy tests (#2862)
+ * test rehab: new flexible run_timeout, speeding up asan, and many more
+ timeouts and test repairs (#2849)
+ * Mypy: add static type checking for python to travis (#2836)
+ * testsuite: minor fixes and slight improvements (#2842)
+ * README: update Travis CI badge after transition to travis-ci.com (#2843)
+ * tests: timeout in automake harness (#2840)
+ * t/t0005-exec: Increase timeout lengths (#2828)
+
+
flux-core version 0.16.0 - 2020-02-24
-------------------------------------
@@ -662,7 +3473,7 @@ flux-core version 0.6.0 - 2016-11-29
* Fix for possible unconstrained memory growth in modules/libjsc (#891)
* Fix error message on flux-help failure (#887)
* Issue fatal error in wrexecd for invalid tasks on node (#901)
- * Fix barrier protocol incompatability with older jansson versions (#889)
+ * Fix barrier protocol incompatibility with older jansson versions (#889)
#### New Features
@@ -701,7 +3512,7 @@ flux-core version 0.5.0 - 2016-10-27
* Add hierarchical lwj directory support in kvs (#811)
* doc/man1/flux-start.adoc: Fix example option usage (#852)
* add dlopen RTLD_DEEPBIND flag (#849)
-* src/broker/broker.c: Fix typo flux_repond -> flux_respond (#851)
+* src/broker/broker.c: Fix typo (#851)
* doc/man1/flux-module.adoc: Fix environment variable error (#850)
* Pull in json-c, allowing internals to link against alternate json libraries. (#835)
* Add enhanced flux_rpc functions using libjansson json_pack/unpack functions
@@ -794,7 +3605,7 @@ flux-core version 0.4.0 - 2016-08-11
* Sophia content backing store module (#727)
-* mrpc KVS based muti-RPC interface (#689)
+* mrpc KVS based multi-RPC interface (#689)
* ZPL config file (#674)
@@ -834,7 +3645,7 @@ flux-core version 0.3.0 - 2016-04-26
* Add module status reporting via keepalive messages.
`flux module list` now reports live module status:
- - I = intializing
+ - I = initializing
- S = sleeping
- X = exited
- R = running
diff --git a/NOTICE b/NOTICE
deleted file mode 120000
index a45239c629bb..000000000000
--- a/NOTICE
+++ /dev/null
@@ -1 +0,0 @@
-NOTICE.LLNS
\ No newline at end of file
diff --git a/README b/README
deleted file mode 100644
index 69b3a83d6de7..000000000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-See the README.md file.
diff --git a/README.md b/README.md
index fd238a789db7..3355fc3b9816 100644
--- a/README.md
+++ b/README.md
@@ -1,194 +1,64 @@
-[![Build Status](https://travis-ci.org/flux-framework/flux-core.svg?branch=master)](https://travis-ci.org/flux-framework/flux-core)
-[![Coverage Status](https://coveralls.io/repos/flux-framework/flux-core/badge.svg?branch=master&service=github)](https://coveralls.io/github/flux-framework/flux-core?branch=master)
+[![ci](https://github.com/flux-framework/flux-core/workflows/ci/badge.svg)](https://github.com/flux-framework/flux-core/actions?query=workflow%3A.github%2Fworkflows%2Fmain.yml)
+[![codecov](https://codecov.io/gh/flux-framework/flux-core/branch/master/graph/badge.svg)](https://codecov.io/gh/flux-framework/flux-core)
-_NOTE: The interfaces of flux-core are being actively developed
-and are not yet stable._ The github issue tracker is the primary
-way to communicate with the developers.
+See our [Online Documentation](https://flux-framework.readthedocs.io)!
-See also the flux-framework.org [Online Documentation](http://flux-framework.org/docs/home/).
+_NOTE: the github issue tracker is the primary way to communicate
+with Flux developers._
-### flux-core
-flux-core implements the communication layer and lowest level
-services and interfaces for the Flux resource manager framework.
-It consists of a distributed message broker, plug-in _comms modules_
-that implement various distributed services, and an API and set
-of utilities to utilize these services.
+### flux-core
-flux-core is intended to be the first building block used in the
-construction of a site-composed Flux resource manager. Other building
-blocks are also in development under the
+flux-core implements the lowest level services and interfaces for the Flux
+resource manager framework. It is intended to be the first building block
+used in the construction of a site-composed Flux resource manager. Other
+building blocks are also in development under the
[flux-framework github organization](https://github.com/flux-framework),
-including a fully functional workload
-[scheduler](https://github.com/flux-framework/flux-sched).
+including a workload [scheduler](https://github.com/flux-framework/flux-sched).
Framework projects use the C4 development model pioneered in
the ZeroMQ project and forked as
-[Flux RFC 1](https://github.com/flux-framework/rfc/blob/master/spec_1.adoc).
+[Flux RFC 1](https://flux-framework.rtfd.io/projects/flux-rfc/en/latest/spec_1.html).
Flux licensing and collaboration plans are described in
-[Flux RFC 2](https://github.com/flux-framework/rfc/blob/master/spec_2.adoc).
+[Flux RFC 2](https://flux-framework.rtfd.io/projects/flux-rfc/en/latest/spec_2.html).
Protocols and API's used in Flux will be documented as Flux RFC's.
#### Build Requirements
-flux-core requires the following packages to build:
-
-**redhat** | **ubuntu** | **version** | **note**
----------- | ---------- | ----------- | --------
-autoconf | autoconf | |
-automake | automake | |
-libtool | libtool | |
-libsodium-devel | libsodium-dev | >= 1.0.14 |
-zeromq4-devel | libzmq3-dev | >= 4.0.4 |
-czmq-devel | libczmq-dev | >= 3.0.1 |
-jansson-devel | libjansson-dev | >= 2.6 |
-libuuid-devel | uuid-dev | |
-lz4-devel | liblz4-dev | |
-hwloc-devel | libhwloc-dev | >= v1.11.1, < 2.0 |
-sqlite-devel | libsqlite3-dev | >= 3.0.0 |
-lua | lua5.1 | >= 5.1, < 5.3 |
-lua-devel | liblua5.1-dev | >= 5.1, < 5.3 |
-lua-posix | lua-posix | | *1*
-python36-devel | python3-dev | >= 2.7 |
-python36-cffi | python3-cffi | >= 1.1 |
-python36-six | python3-six | >= 1.9 |
-python36-yaml | python3-yaml | >= 3.10.0 |
-python36-jsonschema | python3-jsonschema | >= 2.3.0 |
-asciidoc | asciidoc | | *2*
-asciidoctor | asciidoctor | >= 1.5.7 | *2*
-aspell | aspell | | *3*
-valgrind | valgrind | | *3*
-mpich | mpich | | *3*
-jq | jq | | *3*
-
-*Note 1 - Due to a packaging issue, Ubuntu lua-posix may need the
-following symlink (true for version 33.4.0-2):*
-```
-$ sudo ln -s posix_c.so /usr/lib/x86_64-linux-gnu/lua/5.1/posix.so
-```
-
-*Note 2 - only needed if optional man pages are to be created. Only one
-of asciidoc or asciidoctor is needed. Asciidoc is used if both are installed.*
-
-*Note 3 - optional, for enabling additional tests*.
-
-##### Installing RedHat/CentOS Packages
-```
-yum install autoconf automake libtool libsodium-devel zeromq4-devel czmq-devel libuuid-devel jansson-devel lz4-devel hwloc-devel sqlite-devel lua lua-devel lua-posix python36-devel python36-cffi python36-six python36-yaml python36-jsonschema asciidoc asciidoctor aspell valgrind mpich jq
-```
-
-##### Installing Ubuntu Packages
-```
-apt install autoconf automake libtool libsodium-dev libzmq3-dev libczmq-dev uuid-dev libjansson-dev liblz4-dev libhwloc-dev libsqlite3-dev lua5.1 liblua5.1-dev lua-posix python3-dev python3-cffi python3-six python3-yaml python3-jsonschema asciidoc asciidoctor aspell valgrind mpich jq
-```
+For convenience, scripts that install flux-core's build dependencies
+are available for [redhat](scripts/install-deps-rpm.sh) and
+[debian](scripts/install-deps-deb.sh) distros.
##### Building from Source
```
./autogen.sh # skip if building from a release tarball
-PYTHON_VERSION=3.6 ./configure
+./configure
make
make check
```
-Note: the `PYTHON_VERSION` environment variable adds a suffix to the
-python interpreter executable. Configure would look for `python3.6` in
-the example above. If unset, `python` is used, which is often Python 2.
-
-If you want Flux to use Python 2 and generate (only) Python 2 bindings,
-alter the prerequisite package names above, and set (or don't set)
-`PYTHON_VERSION` accordingly. Python 2 support should be considered
-deprecated, although it continues to work for now.
-
-#### Bootstrapping a Flux instance
-A Flux instance is composed of a set of `flux-broker` processes
-that bootstrap via PMI (e.g. under another resource manager), or locally
-via the `flux start` command.
+##### VSCode Dev Containers
-No administrator privilege is required to start a Flux instance
-as described below.
+If you use VSCode we have a dev container and [instructions](vscode.md).
-##### Single node session
+#### Starting Flux
-To start a Flux instance (size = 8) on the local node for testing:
+A Flux instance is composed of a set of `flux-broker` processes running as
+a parallel job and can be started by most launchers that can start MPI jobs.
+Doing so for a single user does not require administrator privilege.
+To start a Flux instance (size = 8) on the local node for testing, use
+flux's built-in test launcher:
```
-src/cmd/flux start --size 8
+src/cmd/flux start --test-size=8
```
-A shell is spawned that has its environment set up so that Flux
-commands can find the message broker socket. When the shell exits,
-the session exits.
-
-##### SLURM session
-
-To start a Flux instance (size = 64) on a cluster using SLURM,
-first ensure that MUNGE is set up on your cluster, then:
-```
-srun --pty --mpi=none -N64 src/cmd/flux start
-```
-The srun --pty option is used to connect to the rank 0 shell.
-When you exit this shell, the session terminates.
-
-#### Flux commands
-
-Within a session, the path to the `flux` command associated with the
-session broker will be prepended to `PATH`, so use of a relative or
-absolute path is no longer necessary.
-
-To see a list of commonly used commands run `flux` with no arguments,
-`flux help`, or `flux --help`
-```
-$ flux help
-Usage: flux [OPTIONS] COMMAND ARGS
- -h, --help Display this message.
- -v, --verbose Be verbose about environment and command search
-
-Common commands from flux-core:
- broker Invoke Flux comms message broker daemon
- content Access instance content storage
- cron Schedule tasks on timers and events
- dmesg manipulate broker log ring buffer
- env Print or run inside a Flux environment
- event Send and receive Flux events
- exec Execute processes across flux ranks
- get,set,lsattr Access, modify, and list broker attributes
- hwloc Control/query resource-hwloc service
- keygen generate keys for Flux security
- kvs Flux key-value store utility
- logger create a Flux log entry
- module manage Flux extension modules
- ping measure round-trip latency to Flux services
- proxy Create proxy environment for Flux instance
- ps List subprocesses managed by brokers
- start bootstrap a local Flux instance
- submit submit job requests to a scheduler
- user Flux user database client
-```
-
-Most of these have UNIX manual pages as `flux-(1)`,
-which can also be accessed using `./flux help `.
-
-#### A note about PMI
-
-When flux is launched, it requires PMI-1 in order to bootstrap.
-It can use PMI-1 in one of two ways, by inheriting a file descriptor
-via the `PMI_FD` environment variable, or by dlopening a PMI library.
-The library name is `libpmi.so`, unless overridden by the `PMI_LIBRARY`
-environment variable. If a PMI library is not found, flux falls back
-to "singleton" operation, where each broker is an independent flux instance.
-The PMI bootstrap may be traced by setting the `FLUX_PMI_DEBUG` environment
-variable.
-
-When flux launches flux or an MPI job, it provides PMI-1 to bootstrap the
-MPI's runtime. It offers a PMI server and sets the `PMI_FD` environment
-variable to point to an open file descriptor connected to it. It also offers
-a `libpmi.so` library that can be dlopened.
+A shell is spawned in which Flux commands can be executed. When the shell
+exits, Flux exits.
-If your system process manager uses PMIx, the `libpmi.so` compatibility library
-provided by the PMIx project should be sufficient to bootstrap flux.
-If your version of PMIx was not built with the compatibility libraries
-installed, you may build libpmix as a separate package to get them installed.
+For more information on starting Flux in various environments and using it,
+please refer to our [docs](https://flux-framework.readthedocs.io) pages.
#### Release
SPDX-License-Identifier: LGPL-3.0
-LLNL-CODE-76440
+LLNL-CODE-764420
diff --git a/autogen.sh b/autogen.sh
index 15729ebd1ca3..d04e30e459ca 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -6,6 +6,6 @@
#
echo "Running libtoolize --automake --copy ... "
libtoolize --automake --copy || exit
-echo "Running autoreconf --verbose --install"
-autoreconf --verbose --install || exit
+echo "Running autoreconf --force --verbose --install"
+autoreconf --force --verbose --install || exit
echo "Now run ./configure."
diff --git a/codecov.yml b/codecov.yml
index af4b65899159..d6dd3d6e1da8 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -9,10 +9,11 @@ coverage:
- ".*/common/libtap/.*"
- ".*/common/liblsd/.*"
- ".*/common/libev/.*"
+ - ".*/common/libtomlc99/.*"
- ".*/common/liboptparse/getopt*"
- - ".*/bindings/python/.*"
- - ".*/common/libutil/sds.*"
- ".*/common/libminilzo/.*"
+ - "src/bindings/python/_flux"
+ - "src/bindings/python/flux/utils"
- "/usr/include/.*"
- "/usr/lib/.*"
@@ -25,3 +26,8 @@ coverage:
comment:
layout: "header, diff, changes, tree"
behavior: new
+ after_n_builds: 2
+
+codecov:
+ notify:
+ after_n_builds: 2
diff --git a/config/ac_pkgconfig.m4 b/config/ac_pkgconfig.m4
index a18523b77c62..da2211f5598b 100644
--- a/config/ac_pkgconfig.m4
+++ b/config/ac_pkgconfig.m4
@@ -5,7 +5,7 @@ AC_DEFUN([AC_PKGCONFIG],
pkgconfigdir='${libdir}/pkgconfig'
AC_MSG_CHECKING(whether to install pkg-config *.pc files)
AC_ARG_WITH(pkgconfig-dir,
- AC_HELP_STRING([--with-pkgconfig-dir=PATH], [where to install pkg-config *.pc files (EPREFIX/lib/pkgconfig)]),
+ AS_HELP_STRING([--with-pkgconfig-dir=PATH],[where to install pkg-config *.pc files (EPREFIX/lib/pkgconfig)]),
[
case "${withval}" in
yes|auto)
diff --git a/config/am_check_pymod.m4 b/config/am_check_pymod.m4
index bcf59cfa7fdb..33c5d1cfb3c2 100644
--- a/config/am_check_pymod.m4
+++ b/config/am_check_pymod.m4
@@ -15,12 +15,15 @@ except:
sys.exit(0)
sys.exit(0)"], [prog="
import sys
-from distutils.version import LooseVersion, StrictVersion
+try:
+ from distutils.version import StrictVersion as Version
+except ModuleNotFoundError:
+ from packaging.version import Version
import $1
if not $2:
sys.exit(1)
"])
-if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC
+if $PYTHON -c "$prog" 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
then
eval "py_cv_mod_$py_mod_var=yes"
else
diff --git a/config/ax_code_coverage.m4 b/config/ax_code_coverage.m4
index 6484f0332435..dbdaf72e537c 100644
--- a/config/ax_code_coverage.m4
+++ b/config/ax_code_coverage.m4
@@ -125,10 +125,10 @@ AC_DEFUN([AX_CODE_COVERAGE],[
dnl Build the code coverage flags
dnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility
CODE_COVERAGE_CPPFLAGS="-DNDEBUG"
- CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
- CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
+ CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage -fprofile-update=atomic"
+ CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage -fprofile-update=atomic"
CODE_COVERAGE_LIBS="-lgcov"
- CODE_COVERAGE_LDFLAGS="$CODE_COVERAGE_LIBS"
+ CODE_COVERAGE_LDFLAGS="$CODE_COVERAGE_LIBS -fprofile-update=atomic"
AC_SUBST([CODE_COVERAGE_CPPFLAGS])
AC_SUBST([CODE_COVERAGE_CFLAGS])
diff --git a/config/ax_compile_check_sizeof.m4 b/config/ax_compile_check_sizeof.m4
index 00d0bcc254ec..f834df6346c9 100644
--- a/config/ax_compile_check_sizeof.m4
+++ b/config/ax_compile_check_sizeof.m4
@@ -1,6 +1,6 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_compile_check_sizeof.html
-# ===========================================================================
+# ============================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_compile_check_sizeof.html
+# ============================================================================
#
# SYNOPSIS
#
@@ -24,8 +24,8 @@
#
# switch (0) case 0: case 0:;
#
-# Thus, the AC_TRY_COMPILE will fail if the currently tried size does not
-# match.
+# Thus, the AC_COMPILE_IFELSE will fail if the currently tried size does
+# not match.
#
# Here is an example skeleton configure.in script, demonstrating the
# macro's usage:
@@ -57,6 +57,7 @@
# LICENSE
#
# Copyright (c) 2008 Kaveh Ghazi
+# Copyright (c) 2017 Reini Urban
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
@@ -69,7 +70,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see .
+# with this program. If not, see .
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -84,7 +85,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 5
+#serial 8
AU_ALIAS([AC_COMPILE_CHECK_SIZEOF], [AX_COMPILE_CHECK_SIZEOF])
AC_DEFUN([AX_COMPILE_CHECK_SIZEOF],
@@ -97,10 +98,10 @@ changequote([, ])dnl
AC_MSG_CHECKING(size of $1)
AC_CACHE_VAL(AC_CV_NAME,
[for ac_size in 4 8 1 2 16 $3 ; do # List sizes in rough order of prevalence.
- AC_TRY_COMPILE([#include "confdefs.h"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include
$2
-], [switch (0) case 0: case (sizeof ($1) == $ac_size):;], AC_CV_NAME=$ac_size)
+]], [[switch (0) case 0: case (sizeof ($1) == $ac_size):;]])], [AC_CV_NAME=$ac_size])
if test x$AC_CV_NAME != x ; then break; fi
done
])
diff --git a/config/ax_python_devel.m4 b/config/ax_python_devel.m4
index 59a2ff090302..1553101afb69 100644
--- a/config/ax_python_devel.m4
+++ b/config/ax_python_devel.m4
@@ -1,10 +1,10 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_python_devel.html
+# https://www.gnu.org/software/autoconf-archive/ax_python_devel.html
# ===========================================================================
#
# SYNOPSIS
#
-# AX_PYTHON_DEVEL([version])
+# AX_PYTHON_DEVEL([version[,optional]])
#
# DESCRIPTION
#
@@ -12,8 +12,8 @@
# in your configure.ac.
#
# This macro checks for Python and tries to get the include path to
-# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS)
-# output variables. It also exports $(PYTHON_EXTRA_LIBS) and
+# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LIBS) output
+# variables. It also exports $(PYTHON_EXTRA_LIBS) and
# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
#
# You can search for some particular version of Python by passing a
@@ -23,6 +23,11 @@
# version number. Don't use "PYTHON_VERSION" for this: that environment
# variable is declared as precious and thus reserved for the end-user.
#
+# By default this will fail if it does not detect a development version of
+# python. If you want it to continue, set optional to true, like
+# AX_PYTHON_DEVEL([], [true]). The ax_python_devel_found variable will be
+# "no" if it fails.
+#
# This macro should work for all versions of Python >= 2.1.0. As an end
# user, you can disable the check for the python version by setting the
# PYTHON_NOVERSIONCHECK environment variable to something else than the
@@ -52,7 +57,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
-# with this program. If not, see .
+# with this program. If not, see .
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@@ -67,10 +72,18 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 17
+#serial 36
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
AC_DEFUN([AX_PYTHON_DEVEL],[
+ # Get whether it's optional
+ if test -z "$2"; then
+ ax_python_devel_optional=false
+ else
+ ax_python_devel_optional=$2
+ fi
+ ax_python_devel_found=yes
+
#
# Allow the use of a (user set) custom python version
#
@@ -81,81 +94,148 @@ AC_DEFUN([AX_PYTHON_DEVEL],[
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
if test -z "$PYTHON"; then
- AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
+ AC_MSG_WARN([Cannot find python$PYTHON_VERSION in your system path])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_ERROR([Giving up, python development not available])
+ fi
+ ax_python_devel_found=no
PYTHON_VERSION=""
fi
- #
- # Check for a version of Python >= 2.1.0
- #
- AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
- ac_supports_python_ver=`$PYTHON -c "import sys; \
+ if test $ax_python_devel_found = yes; then
+ #
+ # Check for a version of Python >= 2.1.0
+ #
+ AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
+ ac_supports_python_ver=`$PYTHON -c "import sys;import setuptools; \
ver = sys.version.split ()[[0]]; \
print (ver >= '2.1.0')"`
- if test "$ac_supports_python_ver" != "True"; then
+ if test "$ac_supports_python_ver" != "True"; then
if test -z "$PYTHON_NOVERSIONCHECK"; then
AC_MSG_RESULT([no])
- AC_MSG_FAILURE([
+ AC_MSG_WARN([
This version of the AC@&t@_PYTHON_DEVEL macro
doesn't work properly with versions of Python before
2.1.0. You may need to re-run configure, setting the
-variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG,
+variables PYTHON_CPPFLAGS, PYTHON_LIBS, PYTHON_SITE_PKG,
PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
to something else than an empty string.
])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_FAILURE([Giving up])
+ fi
+ ax_python_devel_found=no
+ PYTHON_VERSION=""
else
AC_MSG_RESULT([skip at user request])
fi
- else
+ else
AC_MSG_RESULT([yes])
+ fi
fi
- #
- # if the macro parameter ``version'' is set, honour it
- #
- if test -n "$1"; then
+ if test $ax_python_devel_found = yes; then
+ #
+ # If the macro parameter ``version'' is set, honour it.
+ # A Python shim class, VPy, is used to implement correct version comparisons via
+ # string expressions, since e.g. a naive textual ">= 2.7.3" won't work for
+ # Python 2.7.10 (the ".1" being evaluated as less than ".3").
+ #
+ if test -n "$1"; then
AC_MSG_CHECKING([for a version of Python $1])
- ac_supports_python_ver=`$PYTHON -c "import sys; \
- ver = sys.version.split ()[[0]]; \
+ cat << EOF > ax_python_devel_vpy.py
+class VPy:
+ def vtup(self, s):
+ return tuple(map(int, s.strip().replace("rc", ".").split(".")))
+ def __init__(self):
+ import sys
+ import setuptools
+ self.vpy = tuple(sys.version_info)[[:3]]
+ def __eq__(self, s):
+ return self.vpy == self.vtup(s)
+ def __ne__(self, s):
+ return self.vpy != self.vtup(s)
+ def __lt__(self, s):
+ return self.vpy < self.vtup(s)
+ def __gt__(self, s):
+ return self.vpy > self.vtup(s)
+ def __le__(self, s):
+ return self.vpy <= self.vtup(s)
+ def __ge__(self, s):
+ return self.vpy >= self.vtup(s)
+EOF
+ ac_supports_python_ver=`$PYTHON -c "import ax_python_devel_vpy; \
+ ver = ax_python_devel_vpy.VPy(); \
print (ver $1)"`
+ rm -rf ax_python_devel_vpy*.py* __pycache__/ax_python_devel_vpy*.py*
if test "$ac_supports_python_ver" = "True"; then
- AC_MSG_RESULT([yes])
+ AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
- AC_MSG_ERROR([this package requires Python $1.
+ AC_MSG_WARN([this package requires Python $1.
If you have it installed, but it isn't the default Python
interpreter in your system path, please pass the PYTHON_VERSION
variable to configure. See ``configure --help'' for reference.
])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_ERROR([Giving up])
+ fi
+ ax_python_devel_found=no
PYTHON_VERSION=""
fi
+ fi
fi
- #
- # Check if you have distutils, else fail
- #
- AC_MSG_CHECKING([for the distutils Python package])
- ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
- if test -z "$ac_distutils_result"; then
+ if test $ax_python_devel_found = yes; then
+ #
+ # Check if you have distutils, else fail
+ #
+ AC_MSG_CHECKING([for the sysconfig Python package])
+ ac_sysconfig_result=`$PYTHON -c "import sysconfig" 2>&1`
+ if test $? -eq 0; then
AC_MSG_RESULT([yes])
- else
+ IMPORT_SYSCONFIG="import sysconfig"
+ else
AC_MSG_RESULT([no])
- AC_MSG_ERROR([cannot import Python module "distutils".
+
+ AC_MSG_CHECKING([for the distutils Python package])
+ ac_sysconfig_result=`$PYTHON -c "from distutils import sysconfig" 2>&1`
+ if test $? -eq 0; then
+ AC_MSG_RESULT([yes])
+ IMPORT_SYSCONFIG="from distutils import sysconfig"
+ else
+ AC_MSG_WARN([cannot import Python module "distutils".
Please check your Python installation. The error was:
-$ac_distutils_result])
- PYTHON_VERSION=""
+$ac_sysconfig_result])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_ERROR([Giving up])
+ fi
+ ax_python_devel_found=no
+ PYTHON_VERSION=""
+ fi
+ fi
fi
- #
- # Check for Python include path
- #
- AC_MSG_CHECKING([for Python include path])
- if test -z "$PYTHON_CPPFLAGS"; then
- python_path=`$PYTHON -c "import distutils.sysconfig; \
- print (distutils.sysconfig.get_python_inc ());"`
- plat_python_path=`$PYTHON -c "import distutils.sysconfig; \
- print (distutils.sysconfig.get_python_inc (plat_specific=1));"`
+ if test $ax_python_devel_found = yes; then
+ #
+ # Check for Python include path
+ #
+ AC_MSG_CHECKING([for Python include path])
+ if test -z "$PYTHON_CPPFLAGS"; then
+ if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
+ # sysconfig module has different functions
+ python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_path ('include'));"`
+ plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_path ('platinclude'));"`
+ else
+ # old distutils way
+ python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_python_inc ());"`
+ plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
+ print (sysconfig.get_python_inc (plat_specific=1));"`
+ fi
if test -n "${python_path}"; then
if test "${plat_python_path}" != "${python_path}"; then
python_path="-I$python_path -I$plat_python_path"
@@ -164,22 +244,22 @@ $ac_distutils_result])
fi
fi
PYTHON_CPPFLAGS=$python_path
- fi
- AC_MSG_RESULT([$PYTHON_CPPFLAGS])
- AC_SUBST([PYTHON_CPPFLAGS])
+ fi
+ AC_MSG_RESULT([$PYTHON_CPPFLAGS])
+ AC_SUBST([PYTHON_CPPFLAGS])
- #
- # Check for Python library path
- #
- AC_MSG_CHECKING([for Python library path])
- if test -z "$PYTHON_LDFLAGS"; then
+ #
+ # Check for Python library path
+ #
+ AC_MSG_CHECKING([for Python library path])
+ if test -z "$PYTHON_LIBS"; then
# (makes two attempts to ensure we've got a version number
# from the interpreter)
ac_python_version=`cat<]],
[[Py_Initialize();]])
],[pythonexists=yes],[pythonexists=no])
- AC_LANG_POP([C])
- # turn back to default flags
- CPPFLAGS="$ac_save_CPPFLAGS"
- LIBS="$ac_save_LIBS"
+ AC_LANG_POP([C])
+ # turn back to default flags
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBS="$ac_save_LIBS"
+ LDFLAGS="$ac_save_LDFLAGS"
- AC_MSG_RESULT([$pythonexists])
+ AC_MSG_RESULT([$pythonexists])
- if test ! "x$pythonexists" = "xyes"; then
- AC_MSG_FAILURE([
+ if test ! "x$pythonexists" = "xyes"; then
+ AC_MSG_WARN([
Could not link test program to Python. Maybe the main Python library has been
installed in some non-standard library path. If so, pass it to configure,
- via the LDFLAGS environment variable.
- Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
+ via the LIBS environment variable.
+ Example: ./configure LIBS="-L/usr/non-standard-path/python/lib"
============================================================================
ERROR!
You probably have to install the development version of the Python package
for your distribution. The exact name of this package varies among them.
============================================================================
- ])
- PYTHON_VERSION=""
+ ])
+ if ! $ax_python_devel_optional; then
+ AC_MSG_ERROR([Giving up])
+ fi
+ ax_python_devel_found=no
+ PYTHON_VERSION=""
+ fi
fi
#
diff --git a/config/lx_find_mpi.m4 b/config/lx_find_mpi.m4
index fbca314b4e9b..587864d405e4 100644
--- a/config/lx_find_mpi.m4
+++ b/config/lx_find_mpi.m4
@@ -177,17 +177,17 @@ AC_DEFUN([LX_QUERY_MPI_COMPILER],
CPPFLAGS=$MPI_$3FLAGS
LIBS=$MPI_$3LDFLAGS
- AC_TRY_LINK([#include ],
- [int rank, size;
- MPI_Comm_rank(MPI_COMM_WORLD, &rank);
- MPI_Comm_size(MPI_COMM_WORLD, &size);],
- [# Add a define for testing at compile time.
- AC_DEFINE([HAVE_MPI], [1], [Define to 1 if you have MPI libs and headers.])
- have_$3_mpi='yes'],
- [# zero out mpi flags so we don't link against the faulty library.
- MPI_$3FLAGS=""
- MPI_$3LDFLAGS=""
- have_$3_mpi='no'])
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],
+ [[int rank, size;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Comm_size(MPI_COMM_WORLD, &size);]])],
+ [# Add a define for testing at compile time.
+ AC_DEFINE([HAVE_MPI], [1], [Define to 1 if you have MPI libs and headers.])
+ have_$3_mpi='yes'],
+ [# zero out mpi flags so we don't link against the faulty library.
+ MPI_$3FLAGS=""
+ MPI_$3LDFLAGS=""
+ have_$3_mpi='no'])
# AC_SUBST everything.
AC_SUBST($1)
diff --git a/config/tap-driver.py b/config/tap-driver.py
index 02fd5ae02aad..967cf63e5b7a 100644
--- a/config/tap-driver.py
+++ b/config/tap-driver.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-from __future__ import print_function
import sys
import os
diff --git a/config/tap-driver.sh b/config/tap-driver.sh
index 4a687e2d02bb..90e3fce2204b 100755
--- a/config/tap-driver.sh
+++ b/config/tap-driver.sh
@@ -144,7 +144,20 @@ fi
else
exec 2>&3
fi
- "$@"
+ if test -n "${FLUX_TEST_TIMEOUT:-}" ; then
+ if test -z "${FLUX_SOURCE_DIR:-}"; then
+ if test -n "${top_srcdir:-}" ; then
+ FLUX_SOURCE_DIR="$top_srcdir"
+ else
+ SCRIPT=$(readlink -f "$0")
+ SPATH=$(dirname "$SCRIPT")
+ FLUX_SOURCE_DIR="$SPATH"/..
+ fi
+ fi
+ "${PYTHON:-python3}" -S "${FLUX_SOURCE_DIR}/t/scripts/run_timeout.py" "$FLUX_TEST_TIMEOUT" "$@"
+ else
+ "$@"
+ fi
echo $?
) | LC_ALL=C ${AM_TAP_AWK-awk} \
-v me="$me" \
diff --git a/config/x_ac_jansson.m4 b/config/x_ac_jansson.m4
index c076d21429a2..8bcade9efc70 100644
--- a/config/x_ac_jansson.m4
+++ b/config/x_ac_jansson.m4
@@ -1,6 +1,17 @@
+# Versions of jansson shipped by distros:
+# sles15-sp5 ships 2.9 (flux-framework/flux-core#5544)
+# centos7/TOSS3 ships 2.10 (flux-framework/flux-core#3239)
+# centos8/TOSS4 ships 2.11
+# Ubuntu 18.04 ships 2.11
+# Ubuntu 20.04 ships 2.12
+#
+# Some modern jansson features used in flux-core:
+# - json_pack ("O?") from 2.8
+# - json_string_length() from 2.7
+#
AC_DEFUN([X_AC_JANSSON], [
- PKG_CHECK_MODULES([JANSSON], [jansson >= 2.6], [], [])
+ PKG_CHECK_MODULES([JANSSON], [jansson >= 2.9], [], [])
ac_save_LIBS="$LIBS"
LIBS="$LIBS $JANSSON_LIBS"
@@ -13,6 +24,14 @@ AC_DEFUN([X_AC_JANSSON], [
AC_MSG_ERROR([json_int_t must be 64 bits for flux to be built])
])
+ AX_COMPILE_CHECK_SIZEOF(int)
+
+ AS_VAR_IF([ac_cv_sizeof_int],[2],[
+ AC_MSG_ERROR([flux cannot be built on a system with 16 bit ints])
+ ])
+
+ AC_REPLACE_FUNCS(json_object_update_recursive)
+
LIBS="$ac_save_LIBS"
CFLAGS="$ac_save_CFLAGS"
]
diff --git a/config/x_ac_sanitize.m4 b/config/x_ac_sanitize.m4
index e07ef2cecdbd..452c7c567a18 100644
--- a/config/x_ac_sanitize.m4
+++ b/config/x_ac_sanitize.m4
@@ -27,7 +27,7 @@ AC_DEFUN([X_AC_ENABLE_SANITIZER], [
AS_VAR_SET(san_ld_zdef_flag, [])
AC_SUBST(san_ld_zdef_flag)
elif test "x$san_enabled" = "xno" ; then
- AS_VAR_SET(san_ld_zdef_flag, [-Wl,--no-undefined])
+ AS_VAR_SET(san_ld_zdef_flag, [-no-undefined])
AC_SUBST(san_ld_zdef_flag)
else
AC_MSG_ERROR($san_enabled is a unsupported option.)
diff --git a/config/x_ac_zeromq.m4 b/config/x_ac_zeromq.m4
index c42655c5113d..ec2e3996562b 100644
--- a/config/x_ac_zeromq.m4
+++ b/config/x_ac_zeromq.m4
@@ -1,39 +1,35 @@
+# N.B oldest in CI are focal=libzmq-4.3.2-2, centos7=zeromq-4.1.4
+
AC_DEFUN([X_AC_ZEROMQ], [
- PKG_CHECK_MODULES([ZMQ], [libczmq >= 3.0.0 libzmq >= 4.0.4])
+ PKG_CHECK_MODULES([ZMQ], [libzmq >= 4.0.4])
- ac_save_LIBS="$LIBS"
- LIBS="$LIBS $ZMQ_LIBS"
- ac_save_CFLAGS="$CFLAGS"
+ old_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS $ZMQ_CFLAGS"
- AC_MSG_CHECKING([For CURVE encryption support in libzmq])
- AC_CACHE_VAL(ac_cv_curve_support,
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#include
-#include
- main()
- {
- char x[[41]], y[[41]];
- /*
- * Check for CURVE support in current version of libzmq
- */
- int rc = zmq_curve_keypair (x, y);
- exit (rc >= 0 ? 0 : 1);
- }
-]])],
- ac_cv_curve_support=yes,
- ac_cv_curve_support=no,
- ac_cv_curve_support=no))
+ old_LIBS=$LIBS
+ LIBS="$LIBS $ZMQ_LIBS"
+
+ AC_MSG_CHECKING([whether zeromq has CURVE support])
+ AC_RUN_IFELSE([
+ AC_LANG_SOURCE([[
+ #include
+ int main () {
+ char pub[41];
+ char sec[41];
+ if (zmq_curve_keypair (pub, sec) < 0) return 1;
+ return 0;
+ }
+ ]])],
+ [have_zmq_curve_support=yes; AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])]
+ )
- AC_MSG_RESULT($ac_cv_curve_support)
- if test "x$ac_cv_curve_support" = "xno"; then
- AC_MSG_ERROR([
- Failed to detect CURVE support in libzmq!
- Perhaps you need to compile with libsodium?])
- fi
- LIBS="$ac_save_LIBS"
- CFLAGS="$ac_save_CFLAGS"
+ CFLAGS=$old_CFLAGS
+ LIBS=$old_LIBS
+ AS_IF([test "x$have_zmq_curve_support" != "xyes"],
+ [AC_MSG_ERROR([zeromq CURVE/libsodium support is required])]
+ )
]
)
diff --git a/configure.ac b/configure.ac
index ba3a4132b5d5..f70c3c573c34 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,11 +2,11 @@
# Prologue
##
AC_INIT([flux-core],
- m4_esyscmd([git describe --always | awk '/.*/ {sub(/^v/, ""); printf "%s",$1; exit}']))
+ m4_esyscmd([test -n "$FLUX_VERSION" && printf $FLUX_VERSION || git describe --always | awk '/.*/ {sub(/^v/, ""); printf "%s",$1; exit}']))
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_MACRO_DIR([config])
-AC_CONFIG_SRCDIR([NEWS])
-AC_CANONICAL_SYSTEM
+AC_CONFIG_SRCDIR([NEWS.md])
+AC_CANONICAL_TARGET
##
# If runstatedir not explicitly set on command line, use '/run' as default
# N.B. runstatedir is not set at all in autoconf < 2.70.
@@ -19,9 +19,9 @@ X_AC_EXPAND_INSTALL_DIRS
##
# Automake support
##
-AM_INIT_AUTOMAKE([subdir-objects tar-pax])
+AM_INIT_AUTOMAKE([subdir-objects tar-pax foreign])
AM_SILENT_RULES([yes])
-AM_CONFIG_HEADER([config/config.h])
+AC_CONFIG_HEADERS([config/config.h])
AM_MAINTAINER_MODE([enable])
AC_DEFINE([_GNU_SOURCE], 1,
@@ -36,6 +36,28 @@ AC_SUBST([AX_MAJOR_VERSION])
AC_SUBST([AX_MINOR_VERSION])
AC_SUBST([AX_POINT_VERSION])
+AC_MSG_CHECKING([whether version number is sane])
+AS_IF([printf "%d.%d.%d" ${AX_MAJOR_VERSION} ${AX_MINOR_VERSION} ${AX_POINT_VERSION} >/dev/null 2>&1], [
+ AC_MSG_RESULT([yes])
+],[
+ AC_MSG_RESULT([no])
+ version_err_msg="
+ VERSION ${VERSION} is invalid.
+ Try the following to remedy this:
+
+ 1. Run \`git fetch --tags\` before building. Versions in
+ flux-core are derived from \`git describe\` which uses
+ the most recent tag.
+ 2. If you are running remote CI in a fork of the main repository,
+ try pushing the upstream tags to your fork with
+ \`git push --tags \` to make sure tags are
+ synchronized in your fork.
+ 3. Set the variable manually, with FLUX_VERSION=
+ in your environment.
+ "
+ AC_MSG_ERROR(["${version_err_msg}"])
+])
+
##
# Initialize pkg-config for PKG_CHECK_MODULES to avoid conditional issues
##
@@ -85,10 +107,22 @@ LIBFLUX_SCHEDUTIL_AGE=0
LIBFLUX_SCHEDUTIL_VERSION_INFO=$LIBFLUX_SCHEDUTIL_CURRENT:$LIBFLUX_SCHEDUTIL_REVISION:$LIBFLUX_SCHEDUTIL_AGE
AC_SUBST([LIBFLUX_SCHEDUTIL_VERSION_INFO])
+LIBFLUX_HOSTLIST_CURRENT=1
+LIBFLUX_HOSTLIST_REVISION=0
+LIBFLUX_HOSTLIST_AGE=0
+LIBFLUX_HOSTLIST_VERSION_INFO=$LIBFLUX_HOSTLIST_CURRENT:$LIBFLUX_HOSTLIST_REVISION:$LIBFLUX_HOSTLIST_AGE
+AC_SUBST([LIBFLUX_HOSTLIST_VERSION_INFO])
+
+LIBFLUX_TASKMAP_CURRENT=1
+LIBFLUX_TASKMAP_REVISION=0
+LIBFLUX_TASKMAP_AGE=0
+LIBFLUX_TASKMAP_VERSION_INFO=$LIBFLUX_TASKMAP_CURRENT:$LIBFLUX_TASKMAP_REVISION:$LIBFLUX_TASKMAP_AGE
+AC_SUBST([LIBFLUX_TASKMAP_VERSION_INFO])
+
##
# Checks for programs
##
-AC_PROG_CC_C99
+m4_version_prereq(2.70, [AC_PROG_CC], [AC_PROG_CC_C99])
AM_PROG_CC_C_O
AX_COMPILER_VENDOR
AX_COMPILER_VERSION
@@ -132,48 +166,26 @@ AC_PATH_PROGS(SSH, [rsh ssh], [/usr/bin/rsh])
AC_DEFINE_UNQUOTED([PATH_SSH], "$SSH",
[Define remote shell program to be used by the ssh:// connector])
+# macos linker doesn't support --gc-sections
+saved_LDFLAGS="$LDFLAGS"
+LDFLAGS="-Wl,--gc-sections $LDFLAGS"
+AC_MSG_CHECKING([whether ld supports --gc-sections])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([])], [
+ AC_MSG_RESULT([yes])
+ ld_gc_sections="-Wl,--gc-sections"
+ AS_VAR_SET(ld_gc_sections, $ld_gc_sections)
+ AC_SUBST(ld_gc_sections)
+ ],[
+ AC_MSG_RESULT([no])
+])
+LDFLAGS=$saved_LDFLAGS
+
LT_INIT
AC_PROG_AWK
-AC_ARG_ENABLE([docs],
- AS_HELP_STRING([--disable-docs], [disable building docs]))
-AS_IF([test "x$enable_docs" != "xno"], [
- AC_CHECK_PROGS(ADOC, [a2x asciidoctor])
- AS_IF([test "$ADOC" == "a2x"], [
- ADOC_FORMAT_OPT="--format"
- AC_SUBST([ADOC_FORMAT_OPT])
- ])
- AS_IF([test "$ADOC" == "asciidoctor"], [
- AC_MSG_CHECKING([Asciidoctor version])
- ASCIIDOCTOR_VERSION=$(asciidoctor --version|sed -n 's/Asciidoctor \(.*\) .*/\1/p')
- AC_MSG_RESULT([$ASCIIDOCTOR_VERSION])
- AS_IF([test -z "$ASCIIDOCTOR_VERSION"],[
- AC_MSG_ERROR([Failed to read asciidoctor version])
- ])
- AX_COMPARE_VERSION([$ASCIIDOCTOR_VERSION],[ge],[1.5.7], [
- ADOC_FORMAT_OPT="--backend"
- AC_SUBST([ADOC_FORMAT_OPT])
- ],[
- ADOC_ERROR_MSG="asciidoctor version >= 1.5.7 required, got $ASCIIDOCTOR_VERSION"
- AC_MSG_WARN([$ADOC_ERROR_MSG])
- ADOC=""
- ])
- ])
-])
-#
-# If --enable-docs=yes, but no doc generator found,
-# then error immediately:
-#
-AS_IF([test "x$enable_docs" = "xyes" -a -z "$ADOC"],[
- AC_MSG_ERROR([--enable-docs used but no document generator found!])
-])
-AM_CONDITIONAL([ENABLE_DOCS], [test -n "$ADOC"])
-AC_CHECK_PROG(ASPELL,[aspell],[aspell])
-
##
# Checks for header files.
##
-AC_HEADER_STDC
AC_CHECK_HEADERS( \
pthread.h \
getopt.h \
@@ -189,18 +201,25 @@ AC_CHECK_HEADERS( \
xlocale.h \
endian.h \
inttypes.h \
+ link.h \
+ [sys/ucred.h] \
+ [sys/prctl.h] \
)
##
# Checks for typedefs, structures, and compiler characteristics
-##
-AC_C_BIGENDIAN
+##
+AC_C_BIGENDIAN(
+ [AC_DEFINE([HAVE_BIG_ENDIAN], [1], [big endian])],
+ [AC_DEFINE([HAVE_LITTLE_ENDIAN], [1], [little endian])]
+)
AC_C_CONST
AC_TYPE_SIZE_T
AX_COMPILE_CHECK_SIZEOF(int)
AX_COMPILE_CHECK_SIZEOF(long)
AX_COMPILE_CHECK_SIZEOF(long long)
AX_COMPILE_CHECK_SIZEOF(uintptr_t, [#include ])
+AX_COMPILE_CHECK_SIZEOF(ptrdiff_t, [#include ])
AX_COMPILE_CHECK_SIZEOF(size_t, [#include ])
##
@@ -222,14 +241,40 @@ AC_CHECK_FUNCS( \
strncasecmp \
setlocale \
uselocale \
+ inotify_init1 \
+)
+# See src/common/libmissing/Makefile.am
+AC_REPLACE_FUNCS( \
+ strlcpy \
+ strlcat \
+ argz_add \
+ envz_add \
+ strerrorname_np \
+ pipe2 \
+ mempcpy \
+ get_current_dir_name \
)
X_AC_CHECK_PTHREADS
-X_AC_CHECK_COND_LIB(util, forkpty)
X_AC_CHECK_COND_LIB(rt, clock_gettime)
X_AC_CHECK_COND_LIB(dl, dlerror)
X_AC_MALLOC
AC_CHECK_LIB(m, floor)
+AC_SEARCH_LIBS(epoll_create1, epoll-shim)
+AM_CONDITIONAL([HAVE_INOTIFY], [test "x$ac_cv_func_inotify_init1" = xyes])
+
+AC_MSG_CHECKING([for pthread_setname_np with tid parameter])
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [#include ],
+ [pthread_setname_np(pthread_self(), "example")])],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_PTHREAD_SETNAME_NP_WITH_TID, 1,
+ [Have pthread_setname_np() with tid])],
+ [AC_MSG_RESULT(no)]
+)
+AC_ARG_ENABLE([docs],
+ AS_HELP_STRING([--disable-docs], [disable building docs]))
# Edit PATH to remove $PWD/src/cmd so that AM_PATH_PYTHON doesn't find
# flux python script (thus creating a link to itself.) This needs to be
@@ -238,14 +283,21 @@ AC_CHECK_LIB(m, floor)
saved_PATH=$PATH
export PATH=$(echo $PATH | sed "s|$(pwd)/src/cmd:*||")
-AX_PYTHON_DEVEL([>='2.7'])
+if test "X$PYTHON_VERSION" = "X" ; then
+ if test "X$PYTHON" = "X" ; then
+ # if the user hasn't specified, try for python 3
+ PYTHON_VERSION=3
+ fi
+fi
+
+# Do not let AX_PYTHON_DEVEL set PYTHON_SITE_PKG
+saved_PYTHON_SITE_PKG=$PYTHON_SITE_PKG
+AX_PYTHON_DEVEL([>='3.6'])
+PYTHON_SITE_PKG=$saved_PYTHON_SITE_PKG
AM_PATH_PYTHON([$ac_python_version])
if test "X$PYTHON" = "X"; then
- AC_MSG_ERROR([could not find python])
-fi
-if test "X$PYTHON" = "X"; then
- AC_MSG_ERROR([could not find python])
+ AC_MSG_ERROR([could not find python])
fi
# Restore original PATH:
export PATH=${saved_PATH}
@@ -260,28 +312,48 @@ AM_CHECK_PYMOD(cffi,
,
[AC_MSG_ERROR([could not find python module cffi, version 1.1+ required])]
)
-AM_CHECK_PYMOD(six,
- [StrictVersion(six.__version__) >= StrictVersion('1.9.0')],
- ,
- [AC_MSG_ERROR([could not find python module six, version 1.9.0+ required])]
- )
AM_CHECK_PYMOD(yaml,
- [StrictVersion(yaml.__version__) >= StrictVersion ('3.10.0')],
+ [Version(yaml.__version__) >= Version ('3.10.0')],
,
[AC_MSG_ERROR([could not find python module yaml, version 3.10+ required])]
)
-AM_CHECK_PYMOD(jsonschema,
- [StrictVersion(jsonschema.__version__) >= StrictVersion ('2.3.0')],
+AM_CHECK_PYMOD(ply,
+ [Version(ply.__version__) >= Version ('3.9')],
,
- [AC_MSG_ERROR([could not find python module jsonschema, version 2.3.0+ required])]
+ [AC_MSG_ERROR([could not find python module ply, version 3.9+ required])]
)
+AS_IF([test "x$enable_docs" != "xno"], [
+ AM_CHECK_PYMOD(sphinx,
+ [Version(sphinx.__version__) >= Version ('1.6.7')],
+ [sphinx=true],
+ [sphinx=false; AC_MSG_WARN([could not find sphinx to generate docs, version 1.6.7+ required])]
+ )
+ AM_CHECK_PYMOD(docutils,
+ [Version(docutils.__version__) >= Version ('0.11.0')],
+ [docutils=true],
+ [docutils=false; AC_MSG_WARN([could not find docutils to generate docs, version 0.11.0+ required])]
+ )
+])
+# If --enable-docs=yes, but no doc generator found,
+# then error immediately:
+#
+AS_IF([test "x$enable_docs" = "xyes" -a "x$sphinx" = "xfalse"],[
+ AC_MSG_ERROR([--enable-docs used but no document generator found!])
+])
+AS_IF([test "x$enable_docs" = "xyes" -a "x$docutils" = "xfalse"],[
+ AC_MSG_ERROR([--enable-docs used but docutils not found!])
+])
+AM_CONDITIONAL([ENABLE_DOCS], [test "x$sphinx" = "xtrue" -a "x$docutils" = "xtrue"])
+AC_CHECK_PROG(ASPELL,[aspell],[aspell])
+
+
# Remove -L from PYTHON_LDFLAGS if it is in a standard path
# (e.g. /usr/lib64). Placing a standard path earlier in the linker
# search can lead to linking problems.
#
# Logic below assumes only newer Python versions, protected by
-# above check for atleast Python 2.7.
+# above check for atleast Python 3.6.
if test "$ac_python_ldflags_set_by_user" != "true"; then
AC_CHECK_LIB([$ac_python_library], [PyArg_ParseTuple],
[ac_python_in_ld_path=true])
@@ -294,8 +366,6 @@ AS_VAR_SET(fluxpydir, $pyexecdir/flux)
AC_SUBST(fluxpydir)
AS_VAR_SET(fluxpysodir, $pyexecdir/_flux)
AC_SUBST(fluxpysodir)
-AS_VAR_SET(fluxpymoddir, $pyexecdir/flux/modules)
-AC_SUBST(fluxpymoddir)
AC_SUBST(PYTHON_LIBRARY, lib${ac_python_library}.so)
AC_DEFINE_UNQUOTED([PYTHON_INTERPRETER], ["$PYTHON"], [The python interpreter flux is configured with])
@@ -310,23 +380,49 @@ AS_IF([test "x$enable_pylint" = "xyes"], [
AC_CHECK_PROG(PYLINT,[pylint],[pylint])
AS_IF([test "x$PYLINT" != "xpylint"], [AC_MSG_ERROR([No pylint found in PATH])])
AM_CHECK_PYMOD(pylint,
- [StrictVersion(pylint.__version__) >= StrictVersion('1.4.5')],
+ [Version(pylint.__version__) >= Version('1.8.4')],
,
- [AC_MSG_ERROR([could not find python module pylint, version 1.4.5+ required])]
+ [AC_MSG_ERROR([could not find python module pylint, version 1.8.4+ required])]
)
])
AM_CONDITIONAL([ENABLE_PYLINT], [test "x$PYLINT" = "xpylint"])
-AX_PROG_LUA([5.1],[5.4])
+AX_PROG_LUA([5.1],[5.5])
AX_LUA_HEADERS
AX_LUA_LIBS
X_AC_ZEROMQ
X_AC_JANSSON
+PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd >= 0.23],
+ [have_libsystemd=yes], [have_libsystemd=no])
+AC_CHECK_HEADER([systemd/sd-bus.h], [have_sd_bus_h=yes], [have_sd_bus_h=no])
+AM_CONDITIONAL([HAVE_LIBSYSTEMD],
+ [test "$have_libsystemd" = yes -a "$have_sd_bus_h" = yes])
+if test "$have_libsystemd" = yes -a "$have_sd_bus_h" = yes; then
+ AC_DEFINE([HAVE_LIBSYSTEMD], [1], [Define if you have libsystemd])
+ AC_CHECK_LIB(systemd, sd_bus_message_dump,
+ AC_DEFINE([HAVE_SD_BUS_MESSAGE_DUMP], [1],
+ [Define if you have sd_bus_message_dump]))
+fi
PKG_CHECK_MODULES([HWLOC], [hwloc >= 1.11.1], [], [])
PKG_CHECK_MODULES([LZ4], [liblz4], [], [])
PKG_CHECK_MODULES([SQLITE], [sqlite3], [], [])
-PKG_CHECK_MODULES([LIBSODIUM], [libsodium >= 1.0.14], [], [])
PKG_CHECK_MODULES([LIBUUID], [uuid], [], [])
+PKG_CHECK_MODULES([CURSES], [ncursesw], [], [])
+PKG_CHECK_MODULES([LIBARCHIVE], [libarchive], [], [])
+
+AC_ARG_WITH([system-bash-completion-dir],
+ AS_HELP_STRING([--with-system-bash-completion-dir],
+ [Build with system bash-completion dir]))
+AS_IF([test "x$with_system_bash_completion_dir" = "xyes"], [
+ PKG_CHECK_EXISTS([bash-completion],
+ [bashcompdir=`$PKG_CONFIG --variable=completionsdir bash-completion`],
+ [bashcompdir="${sysconfdir}/bash_completion.d"])
+ ], [
+ bashcompdir="${sysconfdir}/bash_completion.d"
+ ]
+)
+AC_SUBST(bashcompdir)
+
LX_FIND_MPI
AM_CONDITIONAL([HAVE_MPI], [test "$have_C_mpi" = yes])
AX_VALGRIND_H
@@ -337,27 +433,47 @@ AS_IF([test x$enable_code_coverage = xyes], [
AC_ARG_WITH([flux-security], AS_HELP_STRING([--with-flux-security],
[Build with flux-security]))
AS_IF([test "x$with_flux_security" = "xyes"], [
- PKG_CHECK_MODULES([FLUX_SECURITY], [flux-security],
- [flux_sec_incdir=`$PKG_CONFIG --variable=includedir flux-security`],
- [flux_sec_incdir=;])
+ PKG_CHECK_MODULES([FLUX_SECURITY], [flux-security >= 0.13.0],
+ [flux_sec_incdir=`$PKG_CONFIG --variable=includedir flux-security`])
AS_IF([test "x$flux_sec_incdir" = x],
- [AC_MSG_ERROR([couldn't find flux-security or include directory])])
+ [AC_MSG_ERROR([couldn't find flux-security include directory])])
AC_CHECK_HEADERS([flux/security/version.h])
AC_DEFINE([HAVE_FLUX_SECURITY], [1], [Define flux-security is available])
AC_SUBST(FLUX_SECURITY_INCDIR, $flux_sec_incdir)
])
AM_CONDITIONAL([HAVE_FLUX_SECURITY], [test "x$with_flux_security" = "xyes"])
-AC_ARG_ENABLE(caliper,
- [ --enable-caliper[=OPTS] Use caliper for profiling. [default=no] [OPTS=no/yes]], ,
- [enable_caliper="no"])
+AC_ARG_ENABLE([content-s3],
+ AS_HELP_STRING([--enable-content-s3], [Enable S3 storage backend]))
+
+AS_IF([test "x$enable_content_s3" = "xyes"], [
+ X_AC_CHECK_COND_LIB(s3, S3_initialize)
+ AS_IF([test "x$ac_cv_lib_s3_S3_initialize" != "xyes"], [
+ AC_MSG_ERROR([configured with --enable-content-s3, but libs3 not found])
+ ])
+
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([#include ],
+ [S3_create_bucket (0,0,0,0,0,0,0,0,0,0,0);])],
+ AC_DEFINE([HAVE_S3_AUTH_REGION], [1], [S3_create_bucket has 11 args]),
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([#include ],
+ [S3_create_bucket (0,0,0,0,0,0,0,0,0,0,0,0,0);])],
+ AC_DEFINE([HAVE_S3_TIMEOUT_ARG], [1], [S3_create_bucket has 13 args])
+ )
+ )
+])
+
+AM_CONDITIONAL([ENABLE_CONTENT_S3], [test "x$enable_content_s3" = "xyes"])
-if test "$enable_caliper" = "yes"; then
- PKG_CHECK_MODULES([CALIPER], [caliper], [], [])
- CFLAGS="${CFLAGS} ${CALIPER_CFLAGS} "
- # Do not use CALIPER_LIBS, only link to libcaliper-stub
- LIBS="${LIBS} $(pkg-config --libs-only-L caliper) -lcaliper-stub -lrt "
- AC_DEFINE([HAVE_CALIPER], [1], [Define if you have libcaliper])
+AC_ARG_ENABLE(
+ [broken-locale-mode],
+ AS_HELP_STRING([--enable-broken-locale-mode],
+ [Assume broken locale config and use ascii only]))
+
+if test "$enable_broken_locale_mode" = "yes"; then
+ AC_DEFINE([ASSUME_BROKEN_LOCALE], [1],
+ [assume broken locale configuration and disable non-ascii characters])
fi
##
@@ -376,38 +492,53 @@ AC_PKGCONFIG
##
# Project directories
##
-AS_VAR_SET(fluxrcdir, $sysconfdir/flux)
-AC_SUBST(fluxrcdir)
-
-AS_VAR_SET(fluxrc1dir, $sysconfdir/flux/rc1.d)
-AC_SUBST(fluxrc1dir)
-
-AS_VAR_SET(fluxrc3dir, $sysconfdir/flux/rc3.d)
-AC_SUBST(fluxrc3dir)
-
-AS_VAR_SET(fluxcfdir, $sysconfdir/flux/conf.d)
-AC_SUBST(fluxcfdir)
-
-AS_VAR_SET(fluxlibexecdir, $libexecdir/flux)
+adl_RECURSIVE_EVAL(["$sysconfdir/flux"], [fluxconfdir])
+AC_DEFINE_UNQUOTED([FLUXCONFDIR], ["$fluxconfdir"],
+ [The expansion of "$sysconfdir/flux"])
+AC_SUBST(fluxconfdir)
+
+adl_RECURSIVE_EVAL(["$libexecdir/flux"], [fluxlibexecdir])
+AC_DEFINE_UNQUOTED([FLUXLIBEXECDIR], ["$fluxlibexecdir"],
+ [The expansion of "$libexecdir/flux"])
AC_SUBST(fluxlibexecdir)
-AS_VAR_SET(fluxcmddir, $libexecdir/flux/cmd)
+adl_RECURSIVE_EVAL(["$libexecdir/flux/cmd"], [fluxcmddir])
+AC_DEFINE_UNQUOTED([FLUXCMDDIR], ["$fluxcmddir"],
+ [The expansion of "$libexecdir/flux/cmd"])
AC_SUBST(fluxcmddir)
-AS_VAR_SET(fluxlibdir, $libdir/flux)
+adl_RECURSIVE_EVAL(["$libdir/flux"], [fluxlibdir])
+AC_DEFINE_UNQUOTED([FLUXLIBDIR], ["$fluxlibdir"],
+ [The expansion of "$libdir/flux"])
AC_SUBST(fluxlibdir)
# Target of PYTHONPATH set by flux(1) cmddriver, so flux(1)
# doesn't inadvertently insert system python paths (or any
# other python path for that matter) first in PYTHONPATH.
#
-AS_VAR_SET(fluxpylinkdir, $fluxlibdir/python$PYTHON_VERSION)
+adl_RECURSIVE_EVAL(["$fluxlibdir/python$PYTHON_VERSION"], [fluxpylinkdir])
+AC_DEFINE_UNQUOTED([FLUXPYLINKDIR], ["$fluxpylinkdir"],
+ [The expansion of "$fluxlibdir/python$PYTHON_VERSION"])
AC_SUBST(fluxpylinkdir)
-AS_VAR_SET(fluxmoddir, $libdir/flux/modules)
+adl_RECURSIVE_EVAL(["$libdir/flux/modules"], [fluxmoddir])
+AC_DEFINE_UNQUOTED([FLUXMODDIR], ["$fluxmoddir"],
+ [The expansion of "$libdir/flux/modules"])
AC_SUBST(fluxmoddir)
-AS_VAR_SET(fluxconnectordir, $libdir/flux/connectors)
+adl_RECURSIVE_EVAL(["$libdir/flux/job-manager/plugins"], [jobtap_plugindir])
+AC_DEFINE_UNQUOTED([JOBTAP_PLUGINDIR], ["$jobtap_plugindir"],
+ [The expansion of "$libdir/flux/job-manager/plugins"])
+AC_SUBST(jobtap_plugindir)
+
+adl_RECURSIVE_EVAL(["$libdir/flux/shell/plugins"], [shell_plugindir])
+AC_DEFINE_UNQUOTED([SHELL_PLUGINDIR], ["$shell_plugindir"],
+ [The expansion of "$libdir/flux/shell/plugins"])
+AC_SUBST(shell_plugindir)
+
+adl_RECURSIVE_EVAL(["$libdir/flux/connectors"], [fluxconnectordir])
+AC_DEFINE_UNQUOTED([FLUXCONNECTORDIR], ["$fluxconnectordir"],
+ [The expansion of "$libdir/flux/connectors"])
AC_SUBST(fluxconnectordir)
AS_VAR_SET(fluxincludedir, $includedir/flux)
@@ -427,13 +558,20 @@ adl_RECURSIVE_EVAL([$luadir], fluxluadir)
AS_VAR_SET(fluxluadir, $fluxluadir)
AC_SUBST(fluxluadir)
+AS_VAR_SET(fluxbindingincludedir, $includedir/flux/_binding)
+AC_SUBST(fluxbindingincludedir)
+
+
##
# Macros to avoid repetition in Makefiles.am's
##
-fluxmod_ldflags="$san_ld_zdef_flag -avoid-version -export-symbols-regex '^mod_(main|name|service)\$\$' --disable-static -shared -export-dynamic"
+fluxmod_ldflags="$san_ld_zdef_flag -avoid-version -export-symbols-regex '^mod_(main|name)\$\$' --disable-static -shared -export-dynamic $ld_gc_sections"
AC_SUBST(fluxmod_ldflags)
-fluxlib_ldflags="-shared -export-dynamic --disable-static $san_ld_zdef_flag"
+fluxplugin_ldflags="-avoid-version -export-symbols-regex '^flux_plugin_init\$\$' --disable-static -shared -export-dynamic $ld_gc_sections"
+AC_SUBST(fluxplugin_ldflags)
+
+fluxlib_ldflags="-shared -export-dynamic --disable-static $san_ld_zdef_flag $ld_gc_sections"
AC_SUBST(fluxlib_ldflags)
##
@@ -450,48 +588,50 @@ AC_CONFIG_FILES( \
src/common/libpmi/Makefile \
src/common/libflux/Makefile \
src/common/libflux/version.h \
+ src/common/libfluxutil/Makefile \
src/common/libtestutil/Makefile \
src/common/libkvs/Makefile \
+ src/common/libcontent/Makefile \
src/common/libjob/Makefile \
src/common/libsubprocess/Makefile \
src/common/liboptparse/Makefile \
src/common/libidset/Makefile \
src/common/libtomlc99/Makefile \
- src/common/libaggregate/Makefile \
src/common/libschedutil/Makefile \
src/common/libeventlog/Makefile \
src/common/libioencode/Makefile \
src/common/librouter/Makefile \
src/common/libyuarel/Makefile \
+ src/common/libdebugged/Makefile \
+ src/common/libterminus/Makefile \
+ src/common/libhostlist/Makefile \
+ src/common/librlist/Makefile \
+ src/common/libczmqcontainers/Makefile \
+ src/common/libccan/Makefile \
+ src/common/libzmqutil/Makefile \
+ src/common/libtaskmap/Makefile \
+ src/common/libfilemap/Makefile \
+ src/common/libsdexec/Makefile \
+ src/common/libmissing/Makefile \
src/bindings/Makefile \
src/bindings/lua/Makefile \
src/bindings/python/Makefile \
src/bindings/python/flux/Makefile \
- src/bindings/python/flux/core/Makefile \
src/bindings/python/_flux/Makefile \
src/broker/Makefile \
src/cmd/Makefile \
src/shell/Makefile \
src/connectors/Makefile \
- src/connectors/local/Makefile \
- src/connectors/shmem/Makefile \
- src/connectors/loop/Makefile \
- src/connectors/ssh/Makefile \
src/modules/Makefile \
- src/modules/connector-local/Makefile \
src/modules/kvs/Makefile \
- src/modules/kvs-watch/Makefile \
- src/modules/content-sqlite/Makefile \
- src/modules/barrier/Makefile \
- src/modules/cron/Makefile \
- src/modules/aggregator/Makefile \
- src/modules/pymod/Makefile \
- src/modules/userdb/Makefile \
+ src/modules/content-files/Makefile \
+ src/modules/content-s3/Makefile \
src/modules/job-ingest/Makefile \
src/modules/job-manager/Makefile \
- src/modules/job-info/Makefile \
+ src/modules/job-list/Makefile \
src/modules/job-exec/Makefile \
- src/modules/sched-simple/Makefile \
+ src/modules/resource/Makefile \
+ src/modules/sdbus/Makefile \
src/test/Makefile \
etc/Makefile \
etc/flux-core.pc \
@@ -499,16 +639,21 @@ AC_CONFIG_FILES( \
etc/flux-optparse.pc \
etc/flux-idset.pc \
etc/flux-schedutil.pc \
+ etc/flux-hostlist.pc \
+ etc/flux-taskmap.pc \
etc/flux.service \
+ etc/flux-housekeeping@.service \
+ src/cmd/flux-run-housekeeping \
+ etc/flux-prolog@.service \
+ etc/flux-epilog@.service \
+ src/cmd/flux-run-prolog \
+ src/cmd/flux-run-epilog \
doc/Makefile \
- doc/man1/Makefile \
- doc/man3/Makefile \
- doc/man5/Makefile \
- doc/man7/Makefile \
doc/test/Makefile \
t/Makefile \
t/fluxometer/conf.lua \
t/fluxometer/conf.lua.installed \
+ src/test/docker/poison-libflux.sh
)
AC_CONFIG_LINKS([ \
@@ -518,7 +663,10 @@ AC_CONFIG_LINKS([ \
AC_OUTPUT
AS_IF([test "x$enable_docs" != "xno"], [
- if test -z "$ADOC"; then
- AC_MSG_WARN([${ADOC_ERROR_MSG:-No asciidoc formatter found}. Manual pages will not be generated.])
+ if test "x$sphinx" = "xfalse"; then
+ AC_MSG_WARN([Python Sphinx not found. Manual pages will not be generated.])
+ elif test "x$docutils" = "xfalse"; then
+ AC_MSG_WARN([Python Docutils not found. Manual pages will not be generated.])
fi
])
+
diff --git a/ChangeLog b/debian/README.Debian
similarity index 100%
rename from ChangeLog
rename to debian/README.Debian
diff --git a/src/modules/pymod/__init__.py b/debian/README.source
similarity index 100%
rename from src/modules/pymod/__init__.py
rename to debian/README.source
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 000000000000..f599e28b8ab0
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+10
diff --git a/debian/control b/debian/control
new file mode 100644
index 000000000000..cb6ec63494c8
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,37 @@
+Source: flux-core
+Section: devel
+Priority: optional
+Maintainer: Mark A. Grondona
+Standards-Version: 4.1.2
+Build-Depends:
+ debhelper (>= 10),
+ flux-security (>= 0.13.0),
+ libarchive-dev,
+ uuid-dev,
+ libzmq3-dev,
+ libjansson-dev,
+ liblz4-dev,
+ libhwloc-dev,
+ libsqlite3-dev,
+ lua5.1,
+ liblua5.1-dev,
+ lua-posix,
+ python3-dev,
+ python3-cffi,
+ python3-yaml,
+ python3-ply,
+ python3-sphinx,
+ jq
+
+Homepage: https://github.com/flux-framework/flux-core
+Package: flux-core
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Core support for the Flux resource manager framework
+ flux-core implements the communication layer and lowest level
+ services and interfaces for the Flux resource manager framework.
+ It consists of a distributed message broker, plug-in modules
+ that implement various distributed services, and an API and set
+ of utilities to utilize these services.
+ Note: This package is for testing purposes only and may not comply
+ with all Debian packaging guidelines.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 000000000000..1724bb2dcaa7
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,77 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: flux-core
+Source:
+
+Files: *
+Copyright: 2014-2023 Lawrence Livermore National Security
+License: LGPL-3+
+
+Files: src/common/libev/*
+Copyright: Copyright (c) 2007-2013 Marc Alexander Lehmann.
+License: BSD-2
+
+Files: src/common/libczmqcontainers/*
+Copyright: Copyright (c) the Contributors as noted in the AUTHORS file.
+License: Mozilla Public License v. 2.0
+
+Files: src/common/libtap/*
+Copyright: Copyright (c) the Contributors as noted in the AUTHORS file.
+License: LGPL
+
+Files: src/common/libtomlc99/*
+Copyright: Copyright (c) 2017 CK Tan
+License: MIT
+
+Files: src/common/libyuarel/*
+Copyright: Copyright (C) 2016,2017 Jack Engqvist Johansson
+License: MIT
+
+Files: src/common/libccan/*
+Copyright: Rusty Russell
+License: CC0
+
+Files: src/common/libccan/bitmap/*
+Copyright: David Gibson
+License: LGPL-2.1+
+
+Files: src/common/libccan/list/*
+Copyright: Rusty Russell
+License: BSD-MIT
+
+Files: src/common/libccan/base64/*
+Copyright: Rusty Russell
+License: BSD-MIT
+
+Files: t/sharness.sh
+Copyright: Copyright (c) 2011-2012 Mathias Lafeldt
+ Copyright (c) 2005-2012 Git project
+ Copyright (c) 2005-2012 Junio C Hamano
+ Copyright (c) 2019-2023 Felipe Contreras
+License: GPL-2.0
+
+Files: src/bindings/python/flux/utils/parsedatetime/*
+Copyright: Copyright 2004-2021 Mike Taylor
+License: Apache-2.0
+
+Files: src/bindings/python/flux/utils/tomli/*
+Copyright: Copyright (c) 2021 Taneli Hukkinen
+License: MIT
+
+Files: debian/*
+Copyright: 2023 Mark A. Grondona
+License: GPL-2+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ .
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
diff --git a/debian/flux-core-docs.docs b/debian/flux-core-docs.docs
new file mode 100644
index 000000000000..86ca00fceb06
--- /dev/null
+++ b/debian/flux-core-docs.docs
@@ -0,0 +1 @@
+README.Debian
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 000000000000..67cb7c0f3455
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,26 @@
+#!/usr/bin/make -f
+# See debhelper(7) (uncomment to enable)
+# output every command that modifies files on the build system.
+#export DH_VERBOSE = 1
+
+# see FEATURE AREAS in dpkg-buildflags(1)
+#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+# see ENVIRONMENT in dpkg-buildflags(1)
+# package maintainers to append CFLAGS
+#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
+# package maintainers to append LDFLAGS
+#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
+
+%:
+ dh $@
+
+override_dh_auto_configure:
+ PYTHON_VERSION=3 dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --with-flux-security
+
+override_dh_autoreconf:
+ @echo not running autogen.sh on dist product
+
+override_dh_auto_install:
+ dh_auto_install
+ find . -name '*.la' -delete
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 000000000000..163aaf8d82b6
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 18751b9cb017..be4447ca1a7c 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1 +1,550 @@
-SUBDIRS = man1 man3 man5 man7 test
+.NOTPARALLEL:
+
+SUBDIRS = . test
+
+MAN_FILES = $(MAN1_FILES) $(MAN3_FILES) $(MAN5_FILES) $(MAN7_FILES)
+
+#######
+# Man 1
+#######
+
+MAN1_FILES = $(MAN1_FILES_PRIMARY) $(MAN1_FILES_SECONDARY)
+
+MAN1_FILES_PRIMARY = \
+ man1/flux.1 \
+ man1/flux-broker.1 \
+ man1/flux-kvs.1 \
+ man1/flux-keygen.1 \
+ man1/flux-logger.1 \
+ man1/flux-overlay.1 \
+ man1/flux-ping.1 \
+ man1/flux-start.1 \
+ man1/flux-startlog.1 \
+ man1/flux-module.1 \
+ man1/flux-exec.1 \
+ man1/flux-env.1 \
+ man1/flux-getattr.1 \
+ man1/flux-dmesg.1 \
+ man1/flux-dump.1 \
+ man1/flux-archive.1 \
+ man1/flux-content.1 \
+ man1/flux-config.1 \
+ man1/flux-proxy.1 \
+ man1/flux-queue.1 \
+ man1/flux-cron.1 \
+ man1/flux-event.1 \
+ man1/flux-submit.1 \
+ man1/flux-run.1 \
+ man1/flux-bulksubmit.1 \
+ man1/flux-alloc.1 \
+ man1/flux-batch.1 \
+ man1/flux-job.1 \
+ man1/flux-version.1 \
+ man1/flux-jobs.1 \
+ man1/flux-pmi.1 \
+ man1/flux-pstree.1 \
+ man1/flux-restore.1 \
+ man1/flux-shell.1 \
+ man1/flux-top.1 \
+ man1/flux-jobtap.1 \
+ man1/flux-shutdown.1 \
+ man1/flux-uptime.1 \
+ man1/flux-uri.1 \
+ man1/flux-resource.1 \
+ man1/flux-pgrep.1 \
+ man1/flux-cancel.1 \
+ man1/flux-watch.1 \
+ man1/flux-update.1 \
+ man1/flux-hostlist.1 \
+ man1/flux-housekeeping.1
+
+# These files are generated as clones of a primary page.
+# Sphinx handles this automatically if declared in the conf.py
+MAN1_FILES_SECONDARY = \
+ man1/flux-setattr.1 \
+ man1/flux-lsattr.1 \
+ man1/flux-pkill.1
+
+
+MAN3_FILES = $(MAN3_FILES_PRIMARY) $(MAN3_FILES_SECONDARY)
+
+MAN3_FILES_PRIMARY = \
+ man3/flux_shell_task_channel_subscribe.3 \
+ man3/flux_shell_add_completion_ref.3 \
+ man3/flux_shell_add_event_context.3 \
+ man3/flux_shell_add_event_handler.3 \
+ man3/flux_shell_aux_set.3 \
+ man3/flux_shell_current_task.3 \
+ man3/flux_shell_get_flux.3 \
+ man3/flux_shell_get_hwloc_xml.3 \
+ man3/flux_shell_get_info.3 \
+ man3/flux_shell_get_jobspec_info.3 \
+ man3/flux_shell_get_taskmap.3 \
+ man3/flux_shell_get_hostlist.3 \
+ man3/flux_shell_getenv.3 \
+ man3/flux_shell_getopt.3 \
+ man3/flux_shell_killall.3 \
+ man3/flux_shell_log.3 \
+ man3/flux_shell_plugstack_call.3 \
+ man3/flux_shell_rpc_pack.3 \
+ man3/flux_shell_service_register.3 \
+ man3/flux_shell_task_get_info.3 \
+ man3/flux_shell_task_subprocess.3 \
+ man3/flux_service_register.3 \
+ man3/flux_open.3 \
+ man3/flux_send.3 \
+ man3/flux_recv.3 \
+ man3/flux_requeue.3 \
+ man3/flux_aux_set.3 \
+ man3/flux_flags_set.3 \
+ man3/flux_comms_error_set.3 \
+ man3/flux_event_subscribe.3 \
+ man3/flux_event_publish.3 \
+ man3/flux_pollevents.3 \
+ man3/flux_msg_encode.3 \
+ man3/flux_msg_has_flag.3 \
+ man3/flux_rpc.3 \
+ man3/flux_get_rank.3 \
+ man3/flux_attr_get.3 \
+ man3/flux_get_reactor.3 \
+ man3/flux_reactor_create.3 \
+ man3/flux_fd_watcher_create.3 \
+ man3/flux_watcher_start.3 \
+ man3/flux_handle_watcher_create.3 \
+ man3/flux_timer_watcher_create.3 \
+ man3/flux_periodic_watcher_create.3 \
+ man3/flux_idle_watcher_create.3 \
+ man3/flux_watcher_set_priority.3 \
+ man3/flux_msg_handler_create.3 \
+ man3/flux_msg_cmp.3 \
+ man3/flux_msg_create.3 \
+ man3/flux_msg_handler_addvec.3 \
+ man3/flux_child_watcher_create.3 \
+ man3/flux_signal_watcher_create.3 \
+ man3/flux_stat_watcher_create.3 \
+ man3/flux_respond.3 \
+ man3/flux_reactor_now.3 \
+ man3/flux_request_decode.3 \
+ man3/flux_event_decode.3 \
+ man3/flux_response_decode.3 \
+ man3/flux_request_encode.3 \
+ man3/flux_log.3 \
+ man3/flux_future_get.3 \
+ man3/flux_future_create.3 \
+ man3/flux_future_wait_all_create.3 \
+ man3/flux_future_and_then.3 \
+ man3/flux_kvs_lookup.3 \
+ man3/flux_kvs_commit.3 \
+ man3/flux_kvs_txn_create.3 \
+ man3/flux_kvs_namespace_create.3 \
+ man3/flux_kvs_getroot.3 \
+ man3/flux_kvs_copy.3 \
+ man3/flux_core_version.3 \
+ man3/hostlist_create.3 \
+ man3/idset_create.3 \
+ man3/idset_encode.3 \
+ man3/idset_decode.3 \
+ man3/idset_add.3 \
+ man3/idset_alloc.3 \
+ man3/flux_jobtap_get_flux.3 \
+ man3/flux_sync_create.3 \
+ man3/flux_job_timeleft.3
+
+
+# These files are generated as clones of a primary page.
+# Sphinx handles this automatically if declared in the conf.py
+MAN3_FILES_SECONDARY = \
+ man3/flux_shell_remove_completion_ref.3 \
+ man3/flux_shell_aux_get.3 \
+ man3/flux_shell_task_first.3 \
+ man3/flux_shell_task_next.3 \
+ man3/flux_shell_info_unpack.3 \
+ man3/flux_shell_jobspec_info_unpack.3 \
+ man3/flux_shell_get_rank_info.3 \
+ man3/flux_shell_rank_info_unpack.3 \
+ man3/flux_shell_get_environ.3 \
+ man3/flux_shell_setenvf.3 \
+ man3/flux_shell_unsetenv.3 \
+ man3/flux_shell_getopt_unpack.3 \
+ man3/flux_shell_setopt.3 \
+ man3/flux_shell_setopt_pack.3 \
+ man3/flux_shell_err.3 \
+ man3/flux_shell_fatal.3 \
+ man3/flux_shell_raise.3 \
+ man3/flux_shell_log_setlevel.3 \
+ man3/flux_shell_task_info_unpack.3 \
+ man3/flux_shell_task_cmd.3 \
+ man3/flux_service_unregister.3 \
+ man3/flux_send_new.3 \
+ man3/flux_clone.3 \
+ man3/flux_close.3 \
+ man3/flux_reconnect.3 \
+ man3/flux_open_ex.3 \
+ man3/flux_aux_get.3 \
+ man3/flux_flags_unset.3 \
+ man3/flux_flags_get.3 \
+ man3/flux_event_unsubscribe.3 \
+ man3/flux_event_publish_pack.3 \
+ man3/flux_event_publish_raw.3 \
+ man3/flux_event_publish_get_seq.3 \
+ man3/flux_pollfd.3 \
+ man3/flux_msg_decode.3 \
+ man3/flux_msg_set_flag.3 \
+ man3/flux_msg_clear_flag.3 \
+ man3/flux_msg_is_private.3 \
+ man3/flux_msg_set_private.3 \
+ man3/flux_msg_is_streaming.3 \
+ man3/flux_msg_set_streaming.3 \
+ man3/flux_msg_is_noresponse.3 \
+ man3/flux_msg_set_noresponse.3 \
+ man3/flux_get_size.3 \
+ man3/flux_attr_set.3 \
+ man3/flux_set_reactor.3 \
+ man3/flux_reactor_destroy.3 \
+ man3/flux_reactor_run.3 \
+ man3/flux_reactor_stop.3 \
+ man3/flux_reactor_stop_error.3 \
+ man3/flux_reactor_active_incref.3 \
+ man3/flux_reactor_active_decref.3 \
+ man3/flux_fd_watcher_get_fd.3 \
+ man3/flux_watcher_stop.3 \
+ man3/flux_watcher_is_active.3 \
+ man3/flux_watcher_destroy.3 \
+ man3/flux_watcher_next_wakeup.3 \
+ man3/flux_handle_watcher_get_flux.3 \
+ man3/flux_timer_watcher_reset.3 \
+ man3/flux_periodic_watcher_reset.3 \
+ man3/flux_prepare_watcher_create.3 \
+ man3/flux_check_watcher_create.3 \
+ man3/flux_msg_handler_destroy.3 \
+ man3/flux_msg_handler_start.3 \
+ man3/flux_msg_handler_stop.3 \
+ man3/flux_msg_handler_delvec.3 \
+ man3/flux_child_watcher_get_rpid.3 \
+ man3/flux_child_watcher_get_rstatus.3 \
+ man3/flux_signal_watcher_get_signum.3 \
+ man3/flux_stat_watcher_get_rstat.3 \
+ man3/flux_respond_raw.3 \
+ man3/flux_respond_pack.3 \
+ man3/flux_respond_error.3 \
+ man3/flux_reactor_now_update.3 \
+ man3/flux_request_unpack.3 \
+ man3/flux_request_decode_raw.3 \
+ man3/flux_event_unpack.3 \
+ man3/flux_event_encode.3 \
+ man3/flux_event_pack.3 \
+ man3/flux_event_encode_raw.3 \
+ man3/flux_event_decode_raw.3 \
+ man3/flux_response_decode_raw.3 \
+ man3/flux_response_decode_error.3 \
+ man3/flux_request_encode_raw.3 \
+ man3/flux_vlog.3 \
+ man3/flux_log_set_appname.3 \
+ man3/flux_log_set_procid.3 \
+ man3/flux_future_then.3 \
+ man3/flux_future_wait_for.3 \
+ man3/flux_future_reset.3 \
+ man3/flux_future_destroy.3 \
+ man3/flux_future_fulfill.3 \
+ man3/flux_future_fulfill_error.3 \
+ man3/flux_future_fulfill_with.3 \
+ man3/flux_future_aux_set.3 \
+ man3/flux_future_aux_get.3 \
+ man3/flux_future_set_flux.3 \
+ man3/flux_future_get_flux.3 \
+ man3/flux_future_wait_any_create.3 \
+ man3/flux_future_push.3 \
+ man3/flux_future_first_child.3 \
+ man3/flux_future_next_child.3 \
+ man3/flux_future_get_child.3 \
+ man3/flux_future_or_then.3 \
+ man3/flux_future_continue.3 \
+ man3/flux_future_continue_error.3 \
+ man3/flux_msg_copy.3 \
+ man3/flux_msg_incref.3 \
+ man3/flux_msg_decref.3 \
+ man3/flux_msg_destroy.3 \
+ man3/flux_rpc_pack.3 \
+ man3/flux_rpc_raw.3 \
+ man3/flux_rpc_message.3 \
+ man3/flux_rpc_get.3 \
+ man3/flux_rpc_get_unpack.3 \
+ man3/flux_rpc_get_raw.3 \
+ man3/flux_rpc_get_matchtag.3 \
+ man3/flux_rpc_get_nodeid.3 \
+ man3/flux_kvs_lookupat.3 \
+ man3/flux_kvs_lookup_get.3 \
+ man3/flux_kvs_lookup_get_unpack.3 \
+ man3/flux_kvs_lookup_get_raw.3 \
+ man3/flux_kvs_lookup_get_dir.3 \
+ man3/flux_kvs_lookup_get_treeobj.3 \
+ man3/flux_kvs_lookup_get_symlink.3 \
+ man3/flux_kvs_getroot_get_treeobj.3 \
+ man3/flux_kvs_getroot_get_blobref.3 \
+ man3/flux_kvs_getroot_get_sequence.3 \
+ man3/flux_kvs_getroot_get_owner.3 \
+ man3/flux_kvs_getroot_cancel.3 \
+ man3/flux_kvs_fence.3 \
+ man3/flux_kvs_commit_get_treeobj.3 \
+ man3/flux_kvs_commit_get_sequence.3 \
+ man3/flux_kvs_txn_destroy.3 \
+ man3/flux_kvs_txn_put.3 \
+ man3/flux_kvs_txn_pack.3 \
+ man3/flux_kvs_txn_vpack.3 \
+ man3/flux_kvs_txn_mkdir.3 \
+ man3/flux_kvs_txn_unlink.3 \
+ man3/flux_kvs_txn_symlink.3 \
+ man3/flux_kvs_txn_put_raw.3 \
+ man3/flux_kvs_txn_put_treeobj.3 \
+ man3/flux_kvs_namespace_remove.3 \
+ man3/flux_kvs_move.3 \
+ man3/flux_core_version_string.3 \
+ man3/hostlist_destroy.3 \
+ man3/hostlist_decode.3 \
+ man3/hostlist_encode.3 \
+ man3/hostlist_copy.3 \
+ man3/hostlist_append.3 \
+ man3/hostlist_append_list.3 \
+ man3/hostlist_nth.3 \
+ man3/hostlist_find.3 \
+ man3/hostlist_delete.3 \
+ man3/hostlist_count.3 \
+ man3/hostlist_sort.3 \
+ man3/hostlist_uniq.3 \
+ man3/hostlist_first.3 \
+ man3/hostlist_last.3 \
+ man3/hostlist_next.3 \
+ man3/hostlist_current.3 \
+ man3/hostlist_remove_current.3 \
+ man3/idset_destroy.3 \
+ man3/idset_decode_ex.3 \
+ man3/idset_decode_empty.3 \
+ man3/idset_decode_info.3 \
+ man3/idset_decode_add.3 \
+ man3/idset_decode_subtract.3 \
+ man3/idset_copy.3 \
+ man3/idset_test.3 \
+ man3/idset_set.3 \
+ man3/idset_range_set.3 \
+ man3/idset_clear.3 \
+ man3/idset_range_clear.3 \
+ man3/idset_first.3 \
+ man3/idset_last.3 \
+ man3/idset_next.3 \
+ man3/idset_prev.3 \
+ man3/idset_empty.3 \
+ man3/idset_universe_size.3 \
+ man3/idset_count.3 \
+ man3/idset_equal.3 \
+ man3/idset_subtract.3 \
+ man3/idset_union.3 \
+ man3/idset_difference.3 \
+ man3/idset_intersect.3 \
+ man3/idset_has_intersection.3 \
+ man3/idset_clear_all.3 \
+ man3/idset_free.3 \
+ man3/idset_free_check.3 \
+ man3/flux_jobtap_service_register.3 \
+ man3/flux_jobtap_reprioritize_all.3 \
+ man3/flux_jobtap_reprioritize_job.3 \
+ man3/flux_jobtap_priority_unavail.3 \
+ man3/flux_jobtap_reject_job.3
+
+MAN5_FILES = $(MAN5_FILES_PRIMARY)
+
+MAN5_FILES_PRIMARY = \
+ man5/flux-config.5 \
+ man5/flux-config-access.5 \
+ man5/flux-config-bootstrap.5 \
+ man5/flux-config-tbon.5 \
+ man5/flux-config-exec.5 \
+ man5/flux-config-systemd.5 \
+ man5/flux-config-resource.5 \
+ man5/flux-config-job-manager.5 \
+ man5/flux-config-ingest.5 \
+ man5/flux-config-kvs.5 \
+ man5/flux-config-policy.5 \
+ man5/flux-config-queues.5
+
+
+MAN7_FILES = $(MAN7_FILES_PRIMARY)
+
+MAN7_FILES_PRIMARY = \
+ man7/flux-broker-attributes.7 \
+ man7/flux-jobtap-plugins.7 \
+ man7/flux-environment.7
+
+
+RST_FILES = \
+ $(MAN1_FILES_PRIMARY:.1=.rst) \
+ $(MAN3_FILES_PRIMARY:.3=.rst) \
+ $(MAN5_FILES_PRIMARY:.5=.rst) \
+ $(MAN7_FILES_PRIMARY:.7=.rst)
+
+if ENABLE_DOCS
+man_MANS = $(MAN1_FILES) $(MAN3_FILES) $(MAN5_FILES) $(MAN7_FILES)
+$(RST_FILES): \
+ man1/common/resources.rst \
+ man1/common/experimental.rst \
+ man1/common/job-param-additional.rst \
+ man1/common/job-param-batch.rst \
+ man1/common/job-param-common.rst \
+ man1/common/job-param-pertask.rst \
+ man1/common/job-param-perres.rst \
+ man1/common/job-standard-io.rst \
+ man1/common/job-constraints.rst \
+ man1/common/job-dependencies.rst \
+ man1/common/job-environment.rst \
+ man1/common/job-env-rules.rst \
+ man1/common/job-environment-variables.rst \
+ man1/common/job-process-resource-limits.rst \
+ man1/common/job-other-options.rst \
+ man1/common/job-other-batch.rst \
+ man1/common/job-other-run.rst \
+ man1/common/job-shell-options.rst \
+ man3/common/resources.rst \
+ man3/common/experimental.rst \
+ man3/common/json_pack.rst \
+ man3/common/json_unpack.rst \
+ man5/common/resources.rst \
+ man5/common/experimental.rst \
+ man7/common/resources.rst \
+ man7/common/experimental.rst
+endif
+
+SUFFIXES = .rst .1 .3 .5 .7
+
+sphinx_man = $(sphinx_man_$(V))
+sphinx_man_ = $(sphinx_man_$(AM_DEFAULT_VERBOSITY))
+sphinx_man_0 = @echo " BUILD manpages";
+
+sphinx_html = $(sphinx_html_$(V))
+sphinx_html_ = $(sphinx_html_$(AM_DEFAULT_VERBOSITY))
+sphinx_html_0 = @echo " BUILD html";
+
+sphinx_verbose_flags = $(sphinx_verbose_flags_$(V))
+sphinx_verbose_flags_ = $(sphinx_verbose_flags_$(AM_DEFAULT_VERBOSITY))
+sphinx_verbose_flags_0 =
+sphinx_verbose_flags_1 = -v
+sphinx_verbose_flags_2 = -vv
+
+STDERR_DEVNULL = $(stderr_devnull_$(V))
+stderr_devnull_ = $(stderr_devnull_$(AM_DEFAULT_VERBOSITY))
+stderr_devnull_0 = >/dev/null 2>&1
+
+$(MAN_FILES): manpages.py conf.py $(RST_FILES)
+ $(sphinx_man) \
+ SPHINX_BUILDDIR=$(abs_builddir) $(PYTHON) \
+ -m sphinx $(sphinx_verbose_flags) -b man $(srcdir) ./man \
+ $(STDERR_DEVNULL)
+ @echo " MV manpages"; \
+ for sec in 1 3 5 7; do \
+ $(MKDIR_P) man$$sec && \
+ mv -f $(abs_builddir)/man/*.$$sec man$$sec/; \
+ done
+
+.PHONY: html
+html: conf.py $(RST_FILES)
+ $(sphinx_html) \
+ SPHINX_BUILDDIR=$(abs_builddir) $(PYTHON) \
+ -m sphinx $(sphinx_verbose_flags) -b html $(srcdir) ./html \
+ $(STDERR_DEVNULL)
+
+EXTRA_DIST = \
+ conf.py \
+ manpages.py \
+ domainrefs.py \
+ index.rst \
+ index_man.rst \
+ requirements.txt \
+ guide/build.rst \
+ guide/support.rst \
+ guide/images/lgplv3-147x51.png \
+ guide/images/adminarch.dia \
+ guide/images/adminarch.png \
+ guide/images/fox-standing.svg \
+ guide/images/Frog-1.svg \
+ guide/images/states.dot \
+ guide/images/states.png \
+ guide/images/states_norm.dot \
+ guide/images/states_norm.png \
+ guide/start.rst \
+ guide/interact.rst \
+ guide/admin.rst \
+ guide/glossary.rst \
+ guide/internals.rst \
+ guide/debug.rst \
+ guide/kvs.rst \
+ guide/broker.rst \
+ $(RST_FILES) \
+ man1/index.rst \
+ man1/common/resources.rst \
+ man1/common/experimental.rst \
+ man1/common/job-param-additional.rst \
+ man1/common/job-param-batch.rst \
+ man1/common/job-param-common.rst \
+ man1/common/job-param-pertask.rst \
+ man1/common/job-param-perres.rst \
+ man1/common/job-standard-io.rst \
+ man1/common/job-constraints.rst \
+ man1/common/job-dependencies.rst \
+ man1/common/job-environment.rst \
+ man1/common/job-env-rules.rst \
+ man1/common/job-environment-variables.rst \
+ man1/common/job-process-resource-limits.rst \
+ man1/common/job-other-options.rst \
+ man1/common/job-other-batch.rst \
+ man1/common/job-other-run.rst \
+ man1/common/job-shell-options.rst \
+ man3/common/resources.rst \
+ man3/common/experimental.rst \
+ man3/index.rst \
+ man3/common/json_pack.rst \
+ man3/common/json_unpack.rst \
+ man5/common/resources.rst \
+ man5/common/experimental.rst \
+ man5/index.rst \
+ man7/index.rst \
+ man7/common/resources.rst \
+ man7/common/experimental.rst \
+ man7/flux-undocumented.rst
+
+CLEANFILES = \
+ $(MAN_FILES)
+
+clean-local:
+ -rm -rf man python/autogenerated
+
+distclean-local:
+ -rm -rf doctrees
+
+# test programs from man3
+AM_CFLAGS = \
+ $(WARNING_CFLAGS) \
+ $(CODE_COVERAGE_CFLAGS)
+
+AM_LDFLAGS = \
+ $(CODE_COVERAGE_LIBS) \
+ -no-install
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src/include \
+ -I$(top_builddir)/src/common/libflux
+
+LDADD = \
+ $(top_builddir)/src/common/libflux-core.la \
+ $(top_builddir)/src/common/libflux-internal.la \
+ $(LIBPTHREAD)
+
+check_PROGRAMS = \
+ man3/example/open \
+ man3/example/send \
+ man3/example/recv \
+ man3/example/event \
+ man3/example/sync \
+ man3/example/rpc \
+ man3/example/rpc_then \
+ man3/example/info
+
+check_HEADERS = man3/example/die.h
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 000000000000..a4c3cb2647c6
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,64 @@
+# Flux Core Documentation
+
+Flux-core documentation currently consists of man pages written in ReStructured Text (rst). The man pages are generated using sphinx and are also hosted at flux-framework.readthedocs.io.
+
+## Build Instructions
+
+To get setup with a virtual environment run:
+
+```bash
+virtualenv -p python3 sphinx-rtd
+source sphinx-rtd/bin/activate
+git clone git@github.com:flux-framework/flux-core
+cd flux-core/doc
+pip install -r requirements.txt
+```
+
+Users can then build the documentation, either as man pages or html web pages.
+Users can also run spellcheck.
+
+```
+sphinx-build -M man ./ _build/
+sphinx-build -M html ./ _build/
+sphinx-build -W -b spelling ./ _build/
+```
+
+## Adding a New Man Page
+
+There are 2 steps to adding a man page:
+- creating the man page documentation file
+- configuring the generation of the man page(s)
+
+### Creating the Man Page
+
+Man pages are written as [ReStructured Text](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html) (`.rst`) files.
+We use [Sphinx](https://www.sphinx-doc.org/en/master/) to process the documentation files and turn them into man pages (troff) and web pages (html).
+
+Sphinx automatically adds the following sections to the generated man page (so do not include them in the `.rst` file):
+
+- `NAME` (first section)
+- `AUTHOR` (penultimate section)
+- `COPYRIGHT` (final section)
+
+Each section title should be underlined with `=`
+
+### Configuring Generation
+
+Generating a man pages is done via the `man_pages` variable in `conf.py`. For example:
+
+```
+man_pages = [
+ ('man1/flux', 'flux', 'the Flux resource management framework', [author], 1),
+]
+```
+
+The tuple entry in the `man_pages` list specifies:
+- File name (relative path, without the `.rst` extension)
+- Name of man page
+- Description of man page
+- Author (use `[author]` as in the example)
+- Manual section for the generated man page
+
+It is possible for multiple man pages to be generated from a single source file.
+Simply create an entry for each man page you want generated.
+These entries can have the same file path, but different man page names.
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 000000000000..74504fa721f9
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,187 @@
+###############################################################
+# Copyright 2020 Lawrence Livermore National Security, LLC
+# (c.f. AUTHORS, NOTICE.LLNS, COPYING)
+#
+# This file is part of the Flux resource manager framework.
+# For details, see https://github.com/flux-framework.
+#
+# SPDX-License-Identifier: LGPL-3.0
+###############################################################
+
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+import os
+import sys
+
+# add `manpages` directory to sys.path
+import pathlib
+sys.path.append(str(pathlib.Path(__file__).absolute().parent))
+
+from manpages import man_pages
+import docutils.nodes
+
+# -- Project information -----------------------------------------------------
+
+project = 'flux-core'
+copyright = '''Copyright 2014 Lawrence Livermore National Security, LLC and Flux developers.
+
+SPDX-License-Identifier: LGPL-3.0'''
+
+# -- General configuration ---------------------------------------------------
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+master_doc = 'index'
+source_suffix = '.rst'
+
+extensions = [
+ 'sphinx.ext.intersphinx',
+ 'sphinx.ext.napoleon',
+ 'domainrefs'
+]
+
+domainrefs = {
+ 'rfc': {
+ 'text': 'RFC %s',
+ 'url': 'https://flux-framework.readthedocs.io/projects/flux-rfc/en/latest/spec_%s.html'
+ },
+ 'linux:man1': {
+ 'text': '%s(1)',
+ 'url': 'https://linux.die.net/man/1/%s',
+ 'url': 'http://man7.org/linux/man-pages/man1/%s.1.html'
+ },
+ 'linux:man2': {
+ 'text': '%s(2)',
+ 'url': 'http://man7.org/linux/man-pages/man2/%s.2.html'
+ },
+ 'linux:man3': {
+ 'text': '%s(3)',
+ 'url': 'http://man7.org/linux/man-pages/man3/%s.3.html'
+ },
+ 'linux:man5': {
+ 'text': '%s(5)',
+ 'url': 'http://man7.org/linux/man-pages/man5/%s.5.html'
+ },
+ 'linux:man7': {
+ 'text': '%s(7)',
+ 'url': 'http://man7.org/linux/man-pages/man7/%s.7.html'
+ },
+ 'linux:man8': {
+ 'text': '%s(8)',
+ 'url': 'http://man7.org/linux/man-pages/man8/%s.8.html'
+ },
+ 'security:man3': {
+ 'text': '%s(3)',
+ 'url': 'https://flux-framework.readthedocs.io/projects/flux-security/en/latest/man3/%s.html'
+ },
+ 'security:man5': {
+ 'text': '%s(5)',
+ 'url': 'https://flux-framework.readthedocs.io/projects/flux-security/en/latest/man5/%s.html'
+ },
+ 'security:man8': {
+ 'text': '%s(8)',
+ 'url': 'https://flux-framework.readthedocs.io/projects/flux-security/en/latest/man8/%s.html'
+ },
+}
+
+# Disable "smartquotes" to avoid things such as turning long-options
+# "--" into en-dash in html output, which won't make much sense for
+# manpages.
+smartquotes = False
+
+# -- Setup for Sphinx API Docs -----------------------------------------------
+
+# Workaround since sphinx does not automatically run apidoc before a build
+# Copied from https://github.com/readthedocs/readthedocs.org/issues/1139
+
+script_dir = os.path.normpath(os.path.dirname(__file__))
+py_bindings_dir = os.path.normpath(os.path.join(script_dir, "../src/bindings/python/"))
+
+# Make sure that the python bindings are in PYTHONPATH for autodoc
+sys.path.insert(0, py_bindings_dir)
+
+# run api doc
+def run_apidoc(_):
+ # Move import inside so that `gen-cmdhelp.py` can exec this file in LGTM.com
+ # without sphinx installed
+ # pylint: disable=import-outside-toplevel
+ from sphinx.ext.apidoc import main
+
+ try:
+ # Check if running under `make`
+ build_dir = os.path.normpath(os.environ.get('SPHINX_BUILDDIR'))
+ except:
+ build_dir = script_dir
+ output_path = os.path.join(build_dir, 'python', 'autogenerated')
+ exclusions = [os.path.join(py_bindings_dir, 'setup.py'),]
+ main(['-e', '-f', '-M', '-T', '-o', output_path, py_bindings_dir] + exclusions)
+
+def man_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+ section = int(name[-1])
+ page = None
+ for man in man_pages:
+ if man[1] == text and man[4] == section:
+ page = man[0]
+ break
+ if page == None:
+ page = "man7/flux-undocumented"
+ section = 7
+
+ node = docutils.nodes.reference(
+ rawsource=rawtext,
+ text=f"{text}({section})",
+ refuri=f"../{page}.html",
+ **options,
+ )
+ return [node], []
+
+# launch setup
+def setup(app):
+ app.connect('builder-inited', run_apidoc)
+ for section in [ 1, 3, 5, 7 ]:
+ app.add_role(f"man{section}", man_role)
+
+# ReadTheDocs runs sphinx without first building Flux, so the cffi modules in
+# `_flux` will not exist, causing import errors. Mock the imports to prevent
+# these errors.
+
+autodoc_mock_imports = ["_flux", "flux.constants", "yaml"]
+
+napoleon_google_docstring = True
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinx_rtd_theme'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+# html_static_path = ['_static']
+
+# -- Options for Intersphinx -------------------------------------------------
+
+intersphinx_mapping = {
+ "rfc": (
+ "https://flux-framework.readthedocs.io/projects/flux-rfc/en/latest/",
+ None,
+ ),
+}
diff --git a/doc/domainrefs.py b/doc/domainrefs.py
new file mode 100644
index 000000000000..5662809e964b
--- /dev/null
+++ b/doc/domainrefs.py
@@ -0,0 +1,72 @@
+"""
+Originally from:
+
+ https://github.com/mitogen-hq/mitogen/blob/master/docs/domainrefs.py
+
+Copyright 2021, the Mitogen authors
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+may be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+import functools
+import re
+
+import docutils.nodes
+import docutils.utils
+
+
+CUSTOM_RE = re.compile('(.*) <(.*)>')
+
+
+def role(config, role, rawtext, text, lineno, inliner, options={}, content=[]):
+ template = 'https://docs.ansible.com/ansible/latest/modules/%s_module.html'
+
+ match = CUSTOM_RE.match(text)
+ if match: # "custom text "
+ title = match.group(1)
+ text = match.group(2)
+ elif text.startswith('~'): # brief
+ text = text[1:]
+ title = config.get('brief', '%s') % (
+ docutils.utils.unescape(text),
+ )
+ else:
+ title = config.get('text', '%s') % (
+ docutils.utils.unescape(text),
+ )
+
+ node = docutils.nodes.reference(
+ rawsource=rawtext,
+ text=title,
+ refuri=config['url'] % (text,),
+ **options
+ )
+
+ return [node], []
+
+
+def setup(app):
+ for name, info in app.config._raw_config['domainrefs'].items():
+ app.add_role(name, functools.partial(role, info))
diff --git a/doc/guide/admin.rst b/doc/guide/admin.rst
new file mode 100644
index 000000000000..b77d38bf2c13
--- /dev/null
+++ b/doc/guide/admin.rst
@@ -0,0 +1,1706 @@
+.. _admin-guide:
+
+##########################
+Flux Administrator's Guide
+##########################
+
+The *Flux Administrator's Guide* documents relevant information for
+installation, configuration, and management of Flux as the native
+resource manager on a cluster.
+
+.. note::
+ Flux is still beta software and many of the interfaces documented
+ in this guide may change with regularity.
+
+***********************
+Overview and Background
+***********************
+
+:doc:`start` and :doc:`interact` provide recipes for starting Flux and
+navigating a hierarchy of Flux instance that do not require administrator
+privilege or configuration. It may be helpful to develop some perspective
+on Flux in these contexts before configuring a Flux system instance.
+
+Flux Architecture
+=================
+
+A *Flux instance* consists of one or more Flux brokers communicating over a
+tree-based overlay network. Most of Flux's distributed systems and services
+that aren't directly associated with a running job are embedded in the
+:man1:`flux-broker` executable or its dynamically loaded plugins.
+
+Flux may be used in *single-user mode*, where a Flux instance is launched as
+a parallel job, and the *instance owner* (the user that submitted the parallel
+job) has control of, and exclusive access to, the Flux instance and its
+assigned resources. On a system running Flux natively, batch jobs and
+allocations are examples of single user Flux instances.
+
+When Flux is deployed as the *system instance*, or native resource manager on
+a cluster, its brokers still run with the credentials of a non-privileged
+system user, typically ``flux``. However, to support multiple users and
+act as a long running service, it must be configured to behave differently:
+
+- The Flux broker is started directly by systemd on each node instead of
+ being launched as a process in a parallel job.
+- The systemd unit file passes arguments to the broker that tell it to use
+ system paths for various files, and to ingest TOML files from a system
+ configuration directory.
+- A single security certificate is used for the entire cluster instead of
+ each broker generating one on the fly and exchanging public keys with PMI.
+- The Flux overlay network endpoints are statically configured from files
+ instead of being generated on on the fly and exchanged via PMI.
+- The instance owner is a system account that does not correspond to an
+ actual user.
+- Users other than the instance owner (*guests*) are permitted to connect
+ to the Flux broker, and are granted limited access to Flux services.
+- Users connect to the Flux broker's AF_UNIX socket via a well known system URI
+ if FLUX_URI is not set in the environment.
+- Job processes (including the Flux job shell) are launched as the submitting
+ user with the assistance of a setuid root helper on each node called the IMP.
+- Job requests are signed with MUNGE, and this signature is verified by the IMP.
+- The content of the Flux KVS, containing system state such as the set of
+ drained nodes and the job queue, is preserved across a full Flux restart.
+- The system instance functions with some nodes offline.
+- The system instance has no *initial program*.
+
+The same Flux executables are used in both single user and system modes,
+with operation differentiated only by configuration.
+
+.. figure:: images/adminarch.png
+ :alt: Flux system instance architecture
+ :align: center
+
+ Fox prevents Frog from submitting jobs on a cluster with Flux
+ as the system resource manager.
+
+Software Components
+===================
+
+Flux was conceived as a resource manager toolkit rather than a monolithic
+project, with the idea to make components like the scheduler replaceable.
+In addition, several parts of flux can be extended with plugins. At this
+time the primary component types are
+
+broker modules
+ Each broker module runs in its own thread as part of the broker executable,
+ communicating with other components using messages. Broker modules are
+ dynamically loadable with the :man1:`flux-module` command. Core
+ services like the KVS, job manager, and scheduler are implemented using
+ broker modules.
+
+jobtap plugins
+ The job manager orchestrates a job's life cycle. Jobtap plugins extend the
+ job manager, arranging for callbacks at different points in the job life
+ cycle. Jobtap plugins may be dynamically loaded with the
+ :man1:`flux-jobtap` command. An example of a jobtap plugin is the Flux
+ accounting multi-factor priority plugin, which updates a job's priority value
+ when it enters the PRIORITY state.
+
+shell plugins
+ When a job is started, the :man1:`flux-shell` is the process parent
+ of job tasks on each node. Shell plugins extend the job environment and
+ can be configured on a per-job basis using the ``--setopt`` option of
+ :man1:`flux-run` and related job submission commands. ``affinity``,
+ ``pmi``, and ``pty`` are examples of Flux shell plugins.
+
+connectors
+ Flux commands open a connection to a particular Flux instance by specifying
+ a URI. The *scheme* portion of the URI may refer to a *native* connection
+ method such as ``local`` or ``ssh``. Native connection methods are
+ implemented as plugins called *connectors*. See :man3:`flux_open`.
+
+URI resolver plugins
+ Other URI schemes must be *resolved* to a native form before they can be used.
+ Resolvers for new schemes may be added as plugins. For example, the ``lsf``
+ resolver plugin enables LSF users to connect to Flux instances running as LSF
+ jobs by specifying a ``lsf:JOBID`` URI. See :man1:`flux-uri`.
+
+validator plugins
+ Jobs may be rejected at ingest if their jobspec fails one of a set of
+ configured validator plugins. The basic validator ensures the jobspec
+ conforms to the jobspec specification. The ``feasibility`` plugin rejects
+ job that the scheduler determines would be unable to run given the instance's
+ resource set. The ``require-instance`` plugin rejects jobs that do not run
+ in a new Flux instance. See :man5:`flux-config-ingest`.
+
+frobnicator plugins
+ The frobnicator allows a set of configured plugins to modify jobspec at
+ submission time. For example the ``defaults`` plugin sets configured default
+ values for jobspec attributes such as *duration* and *queue*. See
+ :man5:`flux-config-ingest`.
+
+Independently developed Flux components are generally packaged and versioned
+separately. Each package may provide one or more of the above components
+as well as man pages and :man1:`flux` subcommands. At this stage of Flux
+development, it is good practice to combine only contemporaneously released
+components as the interfaces are not stable yet.
+
+File Formats and Data Types
+===========================
+
+Since some parts of Flux are developed independently, some effort has been
+made to standardize file formats and data types to ensure components work
+together and provide a consistent user experience. System administrators may
+find it useful to be aware of some of them.
+
+hostlist
+ A compact way of representing an ordered list of hostnames, compatible with
+ legacy tools in use at LLNL and defined by
+ `RFC 29 `_.
+
+idset
+ A compact way of representing an unordered set of integers, defined by
+ `RFC 22 `_.
+
+TOML
+ `Tom's Oblivious Minimal Language `_
+ is the file format used in Flux configuration files.
+
+JSON
+ `Javascript Object Notation `_
+ is used throughout Flux in messages and other file formats.
+
+eventlog
+ An ordered log of timestamped events, stored in the Flux KVS and defined by
+ `RFC 18 `_.
+ Eventlogs are used to record job events, capture standard I/O streams,
+ and record resource status changes.
+
+FSD
+ Flux Standard Duration, a string format used to represent a length of time,
+ defined by
+ `RFC 23 `_.
+
+jobspec
+ A job request (JSON or YAML), defined by
+ `RFC 25 `_ and
+ `RFC 14 `_.
+
+R
+ A resource set (JSON), defined by
+ `RFC 20 `_.
+
+FLUID
+ Flux Locally Unique ID, used for Flux job IDs, defined by
+ `RFC 19 `_.
+
+Security
+========
+
+The Flux brokers that make up a system instance are started on each node by
+systemd. The brokers run as an unprivileged system user, typically ``flux``.
+This user is termed the *instance owner*. The instance owner has complete
+control of the Flux instance.
+
+A tree-based overlay network is established among brokers, rooted at the
+management node. This network is secured and encrypted using the
+`ZeroMQ CURVE `_ mechanism. This requires
+a single CURVE certificate to be generated and installed on all nodes,
+typically ``/etc/flux/system/curve.cert``, before Flux begins operation.
+The certificate must be readable by the instance owner but should be carefully
+protected from access by other users since disclosure could allow overlay
+network security to be bypassed.
+
+On each node, users and tools may connect to the local system instance broker
+via a UNIX domain socket at a well known location, usually ``/run/flux/local``.
+Users are authenticated on this socket using the SO_PEERCRED socket option.
+Once connected, a user may inject messages into the overlay network. Messages
+are stamped by the broker at ingress with the user's authenticated userid,
+and a *role mask* that identifies any special capabilities granted to the user.
+Messages that are sent by the ``flux`` user are stamped with the instance owner
+role, while other users, or *guests*, are stamped with a role that grants
+minimal access. Note that the ``root`` user is considered a guest user with
+no special privilege in Flux, but sites can choose to grant ``root`` the owner
+role by configuration if desired. See :security:man5:`flux-config-security`.
+
+Messages are used for remote procedure calls. A Flux service may allow or deny
+an RPC request depending on its message rolemask or userid. For example,
+only the instance owner can drain a node because the drain service only allows
+drain request messages that have the owner role. Similarly, any job can be
+canceled by a cancel request message with the owner role, but in addition, jobs
+can be canceled by guests whose message userid matches the target job userid.
+
+A Flux job is launched when brokers launch one :man1:`flux-shell` per
+node with the credentials of the user that submitted the job. When that is a
+guest user, Flux employs a setuid helper called the :security:man8:`flux-imp`
+to launch the shells with the guest credentials. The shells in turn launch
+one or more user processes that compose the parallel job.
+
+The IMP is restricted by configuration to only allow the ``flux`` user to run
+it, and to only launch the system Flux job shell executable. In addition, job
+requests are signed by the submitting user with
+`MUNGE `_, and the IMP verifies this signature
+before starting the shells. The current working directory of the job, the
+environment, and the executable command line are examples of job request data
+protected by the MUNGE signature.
+
+When Flux starts a batch job or allocation, it starts an independent,
+single-user Flux instance with brokers running as the submitting user. The new
+instance owner has complete control over this Flux instance, which cannot use
+the IMP to launch jobs as guests, and does not permit guests to connect to
+its UNIX domain sockets. Its overlay network is also secured with the ZeroMQ
+CURVE mechanism, but instead of starting with a shared certificate read from
+disk, each broker generates a certificate in memory on the fly, then exchanges
+public keys and socket endpoints with peer brokers using the PMI service
+offered by the Flux shells of the enclosing instance. In other words, the
+single-user Flux instance bootstraps like an MPI parallel program.
+
+See also:
+`RFC 12 `_,
+`RFC 15 `_.
+
+Overlay Network
+===============
+
+As described above, a Flux instance consists of one or more Flux brokers
+communicating over a tree-based overlay network. A Flux system instance
+on a cluster runs one broker per node. The brokers connect to each other
+using TCP in a static tree topology, which is selected by configuration files.
+The broker at the tree root is the "leader". The others are "followers".
+
+The leader is critical. If it goes down, the entire Flux instance must
+restart. Moreover, an unclean shutdown could result in lost job data.
+Therefore, it is desirable to arrange for the leader to run on a management
+node or other protected server that does not run user workloads.
+
+To a lesser degree, non-leaf follower (internal) nodes are also critical.
+If they are shut down or crash, the subtree rooted at that node must restart.
+However, the Flux instance continues and no data should be lost as long as
+the leader is unaffected.
+
+.. note::
+ At this time, when a node's broker restarts, any jobs running on the node
+ receive a fatal exception. This will be addressed in a future release of
+ Flux that allows job shells to reconnect to the broker after it restarts.
+ For now, it means that restarting the leader affects all running jobs,
+ and restarting a non-leaf follower affects all jobs running on the subtree.
+
+The network used for the overlay network should be chosen for stability,
+as network partitions that persist long enough can cause downstream nodes
+to be declared lost. This has the same effect as crashing. Shorter
+partitions may cause nodes to be marked "torpid" and taken offline temporarily.
+On a cluster, the conservative choice is usually a commodity Ethernet rather
+than a high speed interconnect. Note, however, that partition tolerance can
+be tuned when the network has known issues. See :man5:`flux-config-tbon`.
+
+Topology for Small Clusters
+---------------------------
+
+The overlay topology can be configured in any tree shape. Because of the
+criticality of internal nodes, the *flat* tree with no internal nodes has
+appeal for smaller clusters up to a few hundred nodes. The downsides of
+a *flat* configuration, as the cluster size increases are:
+
+- The leader must directly manage all follower TCP connections. For example,
+ it must iterate over all of them to publish (broadcast) a message.
+
+- The memory footprint of the leader node may grow large due to per-peer
+ message queues.
+
+- The advantages of hierarchical KVS caching are lost. For example, when
+ starting a large job, the leader node must directly service each peer
+ lookup request for the same job data.
+
+- These extra overheads may affect the responsiveness of services that are
+ only present on the leader node, such as the job manager and the scheduler.
+
+The second example in :man5:`flux-config-bootstrap` is a *flat* topology.
+
+Topology for Large Clusters
+---------------------------
+
+To avoid the above downsides, larger clusters should use a custom topology
+with tree height of 2 and internal brokers assigned to stable, well connected,
+non-busy nodes. The downside of this topology is, obviously:
+
+- More brokers are critical
+
+The third example in :man5:`flux-config-bootstrap` is a topology with a tree
+height of 2.
+
+************
+Installation
+************
+
+System Prerequisites
+====================
+
+`MUNGE `_ is used to sign job requests
+submitted to Flux, so the MUNGE daemon should be installed on all
+nodes running Flux with the same MUNGE key used across the cluster.
+
+System clocks must be synchronized across the cluster, e.g. with
+`Network Time Protocol `_.
+
+Flux assumes a shared UID namespace across the cluster.
+
+A system user named ``flux`` is required. This user need not have a valid
+home directory or shell.
+
+Flux uses `hwloc `_ to verify that
+configured resources are present on nodes. Ensure that the system installed
+version includes any plugins needed for the hardware, especially GPUs.
+
+A Word about Core Dumps
+-----------------------
+
+It is helpful to enable core dumps from the system instance ``flux-broker``
+(especially rank 0) so that useful bug reports can be filed should the broker
+crash. Usually :linux:man8:`systemd-coredump` handles this, which makes core
+files and stack traces accessible with :linux:man1:`coredumpctl`.
+
+Some sites choose instead to configure the ``kernel.core_pattern``
+:linux:man8:`sysctl` parameter to a relative file path, which directs core
+files to the program's current working directory. Please note that the system
+instance broker runs as the ``flux`` user with a working directory of ``/``
+and thus would not have write permission on its current working directory.
+This can be worked around by installing a systemd override file, e.g.
+
+.. code-block::
+
+ # /etc/systemd/system/flux.service.d/override.conf
+ [Service]
+ WorkingDirectory=/var/lib/flux
+ LimitCORE=infinity:infinity
+
+.. note::
+ If you do observe a ``flux-broker`` crash, please open a github issue at
+ https://github.com/flux-framework/flux-core/issues and include the Flux
+ version, relevant log messages from ``journalctl -u flux``, and a stack
+ trace, if available.
+
+Installing Software Packages
+============================
+
+The following Flux framework packages are needed for a Flux system instance
+and should be installed from your Linux distribution package manager.
+
+flux-security
+ APIs for job signing, and the IMP, a privileged program for starting
+ processes as multiple users. Install on all nodes (required). If building
+ flux-security from source, be sure to configure with ``--enable-pam`` to
+ include Pluggable Authentication Modules (PAM) support.
+
+flux-core
+ All of the core components of Flux, including the Flux broker.
+ flux-core is functional on its own, but cannot run jobs as multiple users,
+ has a simple FIFO scheduler, and does not implement accounting-based job
+ prioritization. If building flux-core from source, be sure to configure with
+ ``--with-flux-security``. Install on all nodes (required).
+
+flux-sched
+ The Fluxion graph-based scheduler.
+
+flux-accounting (optional)
+ Management of limits for individual users/projects, banks, and prioritization
+ based on fair-share accounting. For more information on how to configure
+ run flux-accounting, please refer to the `Flux Accounting Guide `_.
+
+flux-pam (optional)
+ A PAM module that can enable users to login to compute nodes that are
+ running their jobs.
+
+.. note::
+ Flux packages are currently maintained only for the
+ `TOSS `_
+ Red Hat Enterprise Linux based Linux distribution, which is not publicly
+ distributed. Open an issue in `flux-core `_
+ if you would like to become a maintainer of Flux packages for another Linux
+ distribution so we can share packaging tips and avoid duplicating effort.
+
+
+*************
+Configuration
+*************
+
+Much of Flux configuration occurs via
+`TOML `_ configuration files found in a
+hierarchy under ``/etc/flux``. There are three separate TOML configuration
+spaces: one for flux-security, one for the IMP (an independent component of
+flux-security), and one for Flux running as the system instance. Each
+configuration space has a separate directory, from which all files matching
+the glob ``*.toml`` are read. System administrators have the option of using
+one file for each configuration space, or breaking up each configuration space
+into multiple files. In the examples below, one file per configuration space
+is used.
+
+For more information on the three configuration spaces, please refer to
+:man5:`flux-config`, :security:man5:`flux-config-security`, and
+:security:man5:`flux-config-security-imp`.
+
+Configuring flux-security
+=========================
+
+When Flux is built to support multi-user workloads, job requests are signed
+using a library provided by the flux-security project. This library reads
+a static configuration from ``/etc/flux/security/conf.d/*.toml``. Note
+that for security, these files and their parent directory should be owned
+by ``root`` without write access to other users, so adjust permissions
+accordingly.
+
+Example file installed path: ``/etc/flux/security/conf.d/security.toml``
+
+.. code-block:: toml
+
+ # Job requests should be valid for 2 weeks
+ # Use munge as the job request signing mechanism
+ [sign]
+ max-ttl = 1209600 # 2 weeks
+ default-type = "munge"
+ allowed-types = [ "munge" ]
+
+See also: :security:man5:`flux-config-security-sign`.
+
+Configuring the IMP
+===================
+
+The Independent Minister of Privilege (IMP) is the only program that runs
+as root, by way of the setuid mode bit. To enhance security, it has a
+private configuration space in ``/etc/flux/imp/conf.d/*.toml``. Note that
+the IMP will verify that files in this path and their parent directories
+are owned by ``root`` without write access from other users, so adjust
+permissions and ownership accordingly.
+
+Example file installed path: ``/etc/flux/imp/conf.d/imp.toml``
+
+.. code-block:: toml
+
+ # Only allow access to the IMP exec method by the 'flux' user.
+ # Only allow the installed version of flux-shell(1) to be executed.
+ [exec]
+ allowed-users = [ "flux" ]
+ allowed-shells = [ "/usr/libexec/flux/flux-shell" ]
+
+ # Enable the "flux" PAM stack (requires PAM configuration file)
+ pam-support = true
+
+See also: :security:man5:`flux-config-security-imp`.
+
+Configuring the Flux PAM Stack
+------------------------------
+
+If PAM support is enabled in the IMP config, the ``flux`` PAM stack must
+exist and have at least one ``auth`` and one ``session`` module.
+
+Example file installed path: ``/etc/pam.d/flux``
+
+.. code-block:: console
+
+ auth required pam_localuser.so
+ session required pam_limits.so
+
+The ``pam_limits.so`` module is useful for setting default job resource
+limits. If it is not used, jobs run in the system instance may inherit
+inappropriate limits from ``flux-broker``.
+
+.. note::
+ The linux kernel employs a heuristic when assigning initial limits to
+ pid 1. For example, the max user processes and max pending signals
+ are scaled by the amount of system RAM. The Flux system broker inherits
+ these limits and passes them on to jobs if PAM limits are not configured.
+ This may result in rlimit warning messages similar to
+
+ .. code-block:: console
+
+ flux-shell[0]: WARN: rlimit: nproc exceeds current max, raising value to hard limit
+
+.. _config_cert:
+
+Configuring the Network Certificate
+===================================
+
+Overlay network security requires a certificate to be distributed to all nodes.
+It should be readable only by the ``flux`` user. To create a new certificate,
+run :man1:`flux-keygen` as the ``flux`` user, then copy the result to
+``/etc/flux/system`` since the ``flux`` user will not have write access to
+this location:
+
+.. code-block:: console
+
+ $ sudo -u flux flux keygen /tmp/curve.cert
+ $ sudo mv /tmp/curve.cert /etc/flux/system/curve.cert
+
+Do this once and then copy the certificate to the same location on
+the other nodes, preserving owner and mode.
+
+.. note::
+ The ``flux`` user only needs read access to the certificate and
+ other files and directories under ``/etc/flux``. Keeping these files
+ and directories non-writable by user ``flux`` adds an extra layer of
+ security for the system instance configuration.
+
+Systemd and cgroup unified hierarchy
+====================================
+
+The flux systemd unit launches a systemd user instance as the flux user.
+It is recommended to use this to run user jobs, as it provides cgroups
+containment and the ability to enforce memory limits. To do this, Flux
+requires the cgroup version 2 unified hierarchy:
+
+- The cgroup2 file system must be mounted on ``/sys/fs/cgroup``
+
+- On some systems, add ``systemd.unified_cgroup_hierarchy=1`` to the
+ kernel command line (RHEL 8).
+
+- On some systems, add ``cgroup_enable=memory`` to the kernel command line
+ (debian 12).
+
+The configuration that follows presumes jobs will be launched through systemd,
+although it is not strictly required if your system cannot meet these
+prerequisites.
+
+.. _config-flux:
+
+Configuring the Flux System Instance
+====================================
+
+Although the security components need to be isolated, most Flux components
+share a common configuration space, which for the system instance is located
+in ``/etc/flux/system/conf.d/*.toml``. The Flux broker for the system instance
+is pointed to this configuration by the systemd unit file.
+
+Example file installed path: ``/etc/flux/system/conf.d/system.toml``
+
+.. code-block:: toml
+
+ # Enable the sdbus and sdexec broker modules
+ [systemd]
+ enable = true
+
+ # Flux needs to know the path to the IMP executable
+ [exec]
+ imp = "/usr/libexec/flux/flux-imp"
+
+ # Run jobs in a systemd user instance
+ service = "sdexec"
+
+ # Limit jobs to a percentage of physical memory
+ [exec.sdexec-properties]
+ MemoryMax = "95%"
+
+ # Allow users other than the instance owner (guests) to connect to Flux
+ # Optionally, root may be given "owner privileges" for convenience
+ [access]
+ allow-guest-user = true
+ allow-root-owner = true
+
+ # Point to shared network certificate generated flux-keygen(1).
+ # Define the network endpoints for Flux's tree based overlay network
+ # and inform Flux of the hostnames that will start flux-broker(1).
+ [bootstrap]
+ curve_cert = "/etc/flux/system/curve.cert"
+
+ default_port = 8050
+ default_bind = "tcp://eth0:%p"
+ default_connect = "tcp://%h:%p"
+
+ # Rank 0 is the TBON parent of all brokers unless explicitly set with
+ # parent directives.
+ hosts = [
+ { host = "test[1-16]" },
+ ]
+
+ # Speed up detection of crashed network peers (system default is around 20m)
+ [tbon]
+ tcp_user_timeout = "2m"
+
+ # Uncomment 'norestrict' if flux broker is constrained to system cores by
+ # systemd or other site policy. This allows jobs to run on assigned cores.
+ # Uncomment 'exclude' to avoid scheduling jobs on certain nodes (e.g. login,
+ # management, or service nodes).
+ [resource]
+ #norestrict = true
+ #exclude = "test[1-2]"
+
+ [[resource.config]]
+ hosts = "test[1-15]"
+ cores = "0-7"
+ gpus = "0"
+
+ [[resource.config]]
+ hosts = "test16"
+ cores = "0-63"
+ gpus = "0-1"
+ properties = ["fatnode"]
+
+ # Store the kvs root hash in sqlite periodically in case of broker crash.
+ # Recommend offline KVS garbage collection when commit threshold is reached.
+ [kvs]
+ checkpoint-period = "30m"
+ gc-threshold = 100000
+
+ # Immediately reject jobs with invalid jobspec or unsatisfiable resources
+ [ingest.validator]
+ plugins = [ "jobspec", "feasibility" ]
+
+ # Remove inactive jobs from the KVS after one week.
+ [job-manager]
+ inactive-age-limit = "7d"
+
+ # Jobs submitted without duration get a very short one
+ [policy.jobspec.defaults.system]
+ duration = "1m"
+
+ # Jobs that explicitly request more than the following limits are rejected
+ [policy.limits]
+ duration = "2h"
+ job-size.max.nnodes = 8
+ job-size.max.ncores = 32
+
+ # Configure the flux-sched (fluxion) scheduler policies
+ # The 'lonodex' match policy selects node-exclusive scheduling, and can be
+ # commented out if jobs may share nodes.
+ [sched-fluxion-qmanager]
+ queue-policy = "easy"
+ [sched-fluxion-resource]
+ match-policy = "lonodex"
+ match-format = "rv1_nosched"
+
+See also: :man5:`flux-config-exec`, :man5:`flux-config-access`
+:man5:`flux-config-bootstrap`, :man5:`flux-config-tbon`,
+:man5:`flux-config-resource`, :man5:`flux-config-ingest`,
+:man5:`flux-config-job-manager`,
+:man5:`flux-config-policy`, :man5:`flux-config-kvs`,
+:man5:`flux-config-systemd`,
+:sched:man5:`flux-config-sched-fluxion-qmanager`,
+:sched:man5:`flux-config-sched-fluxion-resource`.
+
+
+Configuring Resources
+=====================
+
+The Flux system instance must be configured with a static resource set.
+The ``resource.config`` TOML array in the example above is the preferred
+way to configure clusters with a resource set consisting of only nodes,
+cores, and GPUs.
+
+More complex resource sets may be represented by generating a file in
+RFC 20 (R version 1) form with scheduler extensions using a combination of
+``flux R encode`` and ``flux ion-R encode`` and then configuring
+``resource.path`` to its fully-qualified file path. The details of this
+method are beyond the scope of this document.
+
+When Flux is running, ``flux resource list`` shows the configured resource
+set and any resource properties.
+
+Persistent Storage on Rank 0
+============================
+
+Flux is prolific in its use of disk space to back up its key value store,
+proportional to the number of jobs run and the quantity of standard I/O.
+On your rank 0 node, ensure that the ``statedir`` directory (normally
+``/var/lib/flux``) has plenty of space and is preserved across Flux instance
+restarts.
+
+The ``statedir`` directory is used for the ``content.sqlite`` file that
+contains content addressable storage backing the Flux key value store (KVS).
+
+Adding Prolog/Epilog/Housekeeping Scripts
+=========================================
+
+Flux can execute site-defined scripts as root on compute nodes before and
+after each job.
+
+prolog
+ The prolog runs as soon as the job enters RUN state. Job shells are not
+ launched until all prolog tasks have completed. If the prolog fails on
+ any nodes, or if any node takes longer than a fail-safe timeout (default
+ 30m), those nodes are drained and a fatal exception is raised on the job.
+ If the job is canceled or reaches its time limit during the prolog, the
+ prolog is simply aborted and the job enters COMPLETING state.
+
+epilog
+ The epilog runs after job shell exits on all nodes, with the job held
+ in COMPLETING state until all epilog tasks have terminated. If the epilog
+ fails on any nodes, those nodes are drained and a fatal exception is raised
+ on the job. There is no default epilog timeout.
+
+housekeeping
+ Housekeeping runs after the job has reached the INACTIVE state. It is not
+ recorded in the job eventlog and does not affect the job result. If
+ housekeeping fails on any nodes, those nodes are drained. Housekeeping
+ releases resources to the scheduler as they complete.
+
+The configuration of prolog, epilog, and housekeeping requires the following
+steps:
+
+ 1. Create executable scripts named ``prolog``, ``epilog``, and
+ ``housekeeping`` in ``/etc/flux/system``. A suggested approach is to have
+ these scripts run all executables found in ``prolog.d``, ``epilog.d``,
+ and ``housekeeping.d`` respectively. For example:
+
+ .. code-block:: sh
+
+ #!/bin/sh
+
+ exit_rc=0
+ periname=prolog
+ peridir=/etc/flux/system/${periname}.d
+
+ # This script may be run in test with 'sudo flux run-prolog'
+ test $FLUX_JOB_USERID && userid=$(id -n -u $FLUX_JOB_USERID 2>/dev/null)
+ echo Running $periname for ${FLUX_JOB_ID:-unknown}/${userid:-unknown}
+
+ for file in ${peridir}/*; do
+ test -e $file || continue
+ name=$(basename $file)
+ echo running $name >&2
+ $file
+ rc=$?
+ test $rc -ne 0 && echo "$name exit $rc" >&2
+ test $rc -gt $exit_rc && exit_rc=$rc
+ done
+
+ exit $exit_rc
+
+ Scripts may use :envvar:`FLUX_JOB_ID` and :envvar:`FLUX_JOB_USERID`
+ to take job or user specific actions. Flux commands can be run from
+ the scripts with instance owner credentials if the system is configured
+ for root access as suggested in :ref:`config-flux`.
+
+ The IMP sets :envvar:`PATH` to a safe ``/usr/sbin:/usr/bin:/sbin:/bin``.
+
+ 2. Flux provides systemd *oneshot* units ``flux-prolog@``, ``flux-epilog@``,
+ and ``flux-housekeeping@`` templated by jobid, which run the user-provided
+ scripts installed in the previous step. Configure the IMP to allow the
+ system instance user to start these units as root via the provided
+ provided wrapper scripts:
+
+ .. code-block:: toml
+
+ [run.prolog]
+ allowed-users = [ "flux" ]
+ allowed-environment = [ "FLUX_*" ]
+ path = "/usr/libexec/flux/cmd/flux-run-prolog"
+
+ [run.epilog]
+ allowed-users = [ "flux" ]
+ allowed-environment = [ "FLUX_*" ]
+ path = "/usr/libexec/flux/cmd/flux-run-epilog"
+
+ [run.housekeeping]
+ allowed-users = [ "flux" ]
+ allowed-environment = [ "FLUX_*" ]
+ path = "/usr/libexec/flux/cmd/flux-run-housekeeping"
+
+
+ 3. Configure the Flux system instance to run prolog, epilog, and housekeeping:
+
+ .. code-block:: toml
+
+ [job-manager]
+ plugins = [
+ { load = "perilog.so" }
+ ]
+
+ [job-manager.prolog]
+ per-rank = true
+ # timeout = "30m"
+
+ [job-manager.epilog]
+ per-rank = true
+ # timeout = "0"
+
+ [job-manager.housekeeping]
+ release-after = "30s"
+
+Standard output and standard error of the prolog, epilog, and housekeeping
+units are captured by the systemd journal. Standard systemd tools like
+:linux:man1:`systemctl` and :linux:man1:`journalctl` can be used to
+observe and manipulate the prolog, epilog, and housekeeping systemd units.
+
+See also:
+:man1:`flux-housekeeping`.
+:man5:`flux-config-job-manager`,
+:security:man5:`flux-config-security-imp`,
+
+Adding Job Request Validation
+=============================
+
+Jobs are submitted to Flux via a job-ingest service. This service
+validates all jobs before they are assigned a jobid and announced to
+the job manager. By default, only basic validation is done, but the
+validator supports plugins so that job ingest validation is configurable.
+
+The list of available plugins can be queried via
+``flux job-validator --list-plugins``. The current list of plugins
+distributed with Flux is shown below:
+
+.. code-block:: console
+
+ $ flux job-validator --list-plugins
+ Available plugins:
+ feasibility Use feasibility service to validate job
+ jobspec Python bindings based jobspec validator
+ require-instance Require that all jobs are new instances of Flux
+ schema Validate jobspec using jsonschema
+
+Only the ``jobspec`` plugin is enabled by default.
+
+In a system instance, it may be useful to also enable the ``feasibility`` and
+``require-instance`` validators. This can be done by configuring the Flux
+system instance via the ``ingest`` TOML table, as shown in the example below:
+
+.. code-block:: toml
+
+ [ingest.validator]
+ plugins = [ "jobspec", "feasibility", "require-instance" ]
+
+The ``feasibility`` plugin will allow the scheduler to reject jobs that
+are not feasible given the current resource configuration. Otherwise, these
+jobs are enqueued, but will have a job exception raised once the job is
+considered for scheduling.
+
+The ``require-instance`` plugin rejects jobs that do not start another
+instance of Flux. That is, jobs are required to be submitted via tools
+like :man1:`flux-batch` and :man1:`flux-alloc`, or the equivalent.
+For example, with this plugin enabled, a user running :man1:`flux-run`
+will have their job rejected with the message:
+
+.. code-block:: console
+
+ $ flux run -n 1000 myapp
+ flux-run: ERROR: [Errno 22] Direct job submission is disabled for this instance. Please use the flux-batch(1) or flux-alloc(1) commands.
+
+See also: :man5:`flux-config-ingest`.
+
+Adding Queues
+=============
+
+It may be useful to configure a Flux system instance with multiple queues.
+Each queue should be associated with a non-overlapping resource subset,
+identified by property name. It is good practice for queues to create a
+new property that has the same name as the queue. (There is no requirement
+that queue properties match the queue name, but this will cause extra entries
+in the PROPERTIES column for these queues. When queue names match property
+names, :command:`flux resource list` suppresses these matching properties
+in its output.)
+
+When queues are defined, all jobs must specify a queue at submission time.
+If that is inconvenient, then ``policy.jobspec.defaults.system.queue`` may
+define a default queue.
+
+Finally, queues can override the ``[policy]`` table on a per queue basis.
+This is useful for setting queue-specific limits.
+
+Here is an example that puts these concepts together:
+
+.. code-block:: toml
+
+ [policy]
+ jobspec.defaults.system.duration = "1m"
+ jobspec.defaults.system.queue = "debug"
+
+ [[resource.config]]
+ hosts = "test[1-4]"
+ properties = ["debug"]
+
+ [[resource.config]]
+ hosts = "test[5-16]"
+ properties = ["batch"]
+
+ [queues.debug]
+ requires = ["debug"]
+ policy.limits.duration = "30m"
+
+ [queues.batch]
+ requires = ["batch"]
+ policy.limits.duration = "4h"
+
+When named queues are configured, :man1:`flux-queue` may be used to
+list them:
+
+.. code-block:: console
+
+ $ flux queue status
+ batch: Job submission is enabled
+ debug: Job submission is enabled
+ Scheduling is enabled
+
+See also: :man5:`flux-config-policy`, :man5:`flux-config-queues`,
+:man5:`flux-config-resource`, :man1:`flux-queue`.
+
+Policy Limits
+=============
+
+Job duration and size are unlimited by default, or limited by the scheduler
+feasibility check discussed above, if configured. When policy limits are
+configured, the job request is compared against them *after* any configured
+jobspec defaults are set, and *before* the scheduler feasibility check.
+If the job would exceed a duration or job size policy limit, the job submission
+is rejected.
+
+.. warning::
+ flux-sched 0.25.0 limitation: jobs that specify nodes but not cores may
+ escape flux-core's ``ncores`` policy limit, and jobs that specify cores but
+ not nodes may escape the ``nnodes`` policy limit. The flux-sched feasibility
+ check will eventually cover this case. Until then, be sure to set both
+ ``nnodes`` *and* ``ncores`` limits when configuring job size policy limits.
+
+Limits are global when set in the top level ``[policy]`` table. Global limits
+may be overridden by a ``policy`` table within a ``[queues]`` entry. Here is
+an example which implements duration and job size limits for two queues:
+
+.. code-block:: toml
+
+ # Global defaults
+ [policy]
+ jobspec.defaults.system.duration = "1m"
+ jobspec.defaults.system.queue = "debug"
+
+ [queues.debug]
+ requires = ["debug"]
+ policy.limits.duration = "30m"
+ policy.limits.job-size.max.nnodes = 2
+ policy.limits.job-size.max.ncores = 16
+
+ [queues.batch]
+ requires = ["batch"]
+ policy.limits.duration = "8h"
+ policy.limits.job-size.max.nnodes = 16
+ policy.limits.job-size.max.ncores = 128
+
+See also: :man5:`flux-config-policy`.
+
+Use PAM to Restrict Access to Compute Nodes
+===========================================
+
+If Pluggable Authentication Modules (PAM) are in use within a cluster, it may
+be convenient to use the ``pam_flux.so`` *account* module to configure a PAM
+stack that denies users access to compute nodes unless they have a job running
+there.
+
+Install the ``flux-pam`` package to make the ``pam_flux.so`` module available
+to be added to one or more PAM stacks, e.g.
+
+.. code-block:: console
+
+ account sufficient pam_flux.so
+
+********************
+Pre-flight Checklist
+********************
+
+Here are some things to check before going live with a new Flux system
+instance.
+
+Do I have all the right packages installed?
+===========================================
+
+Flux packages should be installed on all nodes.
+
+.. list-table::
+ :header-rows: 1
+
+ * - Package name
+ * - flux-core
+ * - flux-security
+ * - flux-sched
+ * - flux-pam (optional)
+ * - flux-accounting (optional)
+
+Does /var/lib/flux have plenty of space on the leader node?
+===========================================================
+
+Flux stores its databases and KVS dumps in the ``statedir`` on the
+leader (management) node. Storage consumption depends on usage, the
+size of the cluster, and other factors but be generous as running out
+of space on the leader node is catastrophic to Flux.
+
+The ``statedir`` is created automatically by systemd if it does not
+exist when Flux is started. If you are creating it, it should be owned
+by the ``flux`` user and private to that user.
+
+Is Munge working?
+=================
+
+Munge daemons must be running on every node, clocks must be synchronized,
+and all nodes should be using the same pre-shared munge key.
+
+.. code-block:: console
+
+ $ pdsh -a systemctl is-active munge | dshbak -c
+ ----------------
+ test[0-7]
+ ----------------
+ active
+
+ $ pdsh -a "timedatectl | grep synchronized:" | dshbak -c
+ ----------------
+ test[0-7]
+ ----------------
+ System clock synchronized: yes
+
+ # spot check
+ $ echo xyz | ssh test1 munge | ssh test2 unmunge
+ STATUS: Success (0)
+ ENCODE_HOST: test1 (192.168.88.246)
+ ENCODE_TIME: 2024-04-18 09:41:21 -0700 (1713458481)
+ DECODE_TIME: 2024-04-18 09:41:21 -0700 (1713458481)
+ TTL: 300
+ CIPHER: aes128 (4)
+ MAC: sha256 (5)
+ ZIP: none (0)
+ UID: testuser (100)
+ GID: testuser (100)
+ LENGTH: 4
+
+Are users set up properly?
+==========================
+
+Flux requires that the ``flux`` user and all other users that will be
+using Flux have the a consistent UID assignment across the cluster.
+
+.. code-block:: console
+
+ $ pdsh -a id flux | dshbak -c
+ ----------------
+ test[0-7]
+ ----------------
+ uid=500(flux) gid=500(flux) groups=500(flux)
+
+Is the Flux network certificate synced?
+=======================================
+
+The network certificate should be identical on all nodes and should
+only be readable by the ``flux`` user:
+
+.. code-block:: console
+
+ $ sudo pdsh -a md5sum /etc/flux/system/curve.cert | dshbak -c
+ ----------------
+ test[0-7]
+ ----------------
+ 1b3c226159b9041d357a924841845cec /etc/flux/system/curve.cert
+
+ $ pdsh -a stat -c '"%U %A"' /etc/flux/system/curve.cert | dshbak -c
+ ----------------
+ test[0-7]
+ ----------------
+ flux -r--------
+
+See :ref:`config_cert`.
+
+Is the Flux configuration synced?
+=================================
+
+The Flux configurations for system, security, and imp should
+be identical on all nodes, owned by root, and publicly readable:
+
+
+.. code-block:: console
+
+ $ pdsh -a "flux config get --config-path=system | md5sum" | dshbak -c
+ ----------------
+ test[1-7]
+ ----------------
+ 432378ee4f210a879162e1ac66465c0e -
+ $ pdsh -a "flux config get --config-path=security | md5sum" |dshbak -c
+ ----------------
+ test[1-7]
+ ----------------
+ 1c53f68eea714a1b0641f201130e0d29 -
+ $ pdsh -a "flux config get --config-path=imp | md5sum" |dshbak -c
+ ----------------
+ test[0-7]
+ ----------------
+ e69c9d49356f4f1ecb76befdac727ef4 -
+
+ $ pdsh -a stat -c '"%U %A"' /etc/flux/system/conf.d /etc/flux/security/conf.d /etc/flux/imp/conf.d |dshbak -c
+ ----------------
+ test[0-7]
+ ----------------
+ root drwxr-xr-x
+ root drwxr-xr-x
+ root drwxr-xr-x
+
+Will the network be able to wire up?
+====================================
+
+Check your firewall rules and DNS/hosts configuration to ensure that each
+broker will be able to look up and connect to its configured parent in the
+tree based overlay network using TCP.
+
+Will the network stay up?
+=========================
+
+Although TCP is a reliable transport, the network used by the Flux overlay
+should be stable, otherwise:
+
+- Nodes can be temporarily marked offline for scheduling if the Flux broker
+ remains connected but cannot get messages through promptly. This may be
+ tuned with ``tbon.torpid_max``.
+
+- Nodes can be disconnected (and running jobs lost) when TCP acknowledgements
+ cannot get through in time. For example, this may happen during a network
+ partition. This may be tuned with ``tbon.tcp_user_timeout``.
+
+If the network is expected to be unstable (e.g. while the bugs are worked
+out of new hardware), then the above values may need to be temporarily
+increased to avoid nuisance failures. See :man5:`flux-config-tbon`.
+
+Is the Flux resource configuration correct?
+===========================================
+
+Ensure all nodes have the same resource configuration and that the summary
+looks sane:
+
+.. code-block:: console
+
+ $ pdsh -a "flux R parse-config /etc/flux/system/conf.d | flux R decode --short" | dshbak -c
+ ----------------
+ test[0-7]
+ ----------------
+ rank[0-7]/core[0-3]
+
+ $ pdsh -a "flux R parse-config /etc/flux/system/conf.d | flux R decode --nodelist" | dshbak -c
+ ----------------
+ test[0-7]
+ ----------------
+ test[0-7]
+
+Does the leader broker start?
+=============================
+
+Try to start the leader (rank 0) broker on the management node.
+
+.. code-block:: console
+
+ $ sudo systemctl start flux
+ $ flux uptime
+ 07:42:52 run 3.8s, owner flux, depth 0, size 8, 7 offline
+ $ systemctl status flux
+ â flux.service - Flux message broker
+ Loaded: loaded (/lib/systemd/system/flux.service; enabled; vendor preset: enabled)
+ Active: active (running) since Tue 2024-04-23 07:36:44 PDT; 37s ago
+ Process: 287736 ExecStartPre=/usr/bin/loginctl enable-linger flux (code=exited, status=0/SUCCESS)
+ Process: 287737 ExecStartPre=bash -c systemctl start user@$(id -u flux).service (code=exited, status=0/SUCCESS)
+ Main PID: 287739 (flux-broker-0)
+ Status: "Running as leader of 8 node Flux instance"
+ Tasks: 22 (limit: 8755)
+ Memory: 26.6M
+ CPU: 3.506s
+ CGroup: /system.slice/flux.service
+ ââ287739 broker --config-path=/etc/flux/system/conf.d -Scron.directory=/etc/flux/system/cron.d -Srundir=/run/flux -Sstatedir=/var/lib/flux -Slocal-uri=local:///run/flux/local -Slog-stderr-level=6 -Slog-stderr-mode=local -Sbroker.rc2_none -Sbroker.quorum=1 -Sbroker.quorum-timeout=none -Sbroker.exit-norestart=42 -Sbroker.sd-notify=1 -Scontent.dump=auto -Scontent.restore=auto
+
+ Apr 23 07:36:46 test0 flux[287739]: sched-fluxion-resource.info[0]: version 0.33.1-40-g24255b38
+ Apr 23 07:36:46 test0 flux[287739]: sched-fluxion-qmanager.info[0]: version 0.33.1-40-g24255b38
+ Apr 23 07:36:46 test0 flux[287739]: broker.info[0]: rc1.0: running /etc/flux/rc1.d/02-cron
+ Apr 23 07:36:47 test0 flux[287739]: broker.info[0]: rc1.0: /etc/flux/rc1 Exited (rc=0) 2.6s
+ Apr 23 07:36:47 test0 flux[287739]: broker.info[0]: rc1-success: init->quorum 2.65475s
+ Apr 23 07:36:47 test0 flux[287739]: broker.info[0]: online: test0 (ranks 0)
+ Apr 23 07:36:47 test0 flux[287739]: broker.info[0]: quorum-full: quorum->run 0.102056s
+
+Do other nodes join?
+====================
+
+Bring up a follower node that is configured with the leader as its parent
+in the tree based overlay network:
+
+.. code-block:: console
+
+ $ ssh test1
+ $ sudo systemctl start flux
+ $ flux uptime
+ 07:47:58 run 4.3m, owner flux, depth 0, size 8, 6 offline
+ $ flux overlay status
+ 0 test0: partial
+ ââ 1 test1: partial
+ â ââ 3 test3: offline
+ â ââ 4 test4: offline
+ â ââ 5 test5: offline
+ ââ 2 test2: offline
+ ââ 6 test6: offline
+ ââ 7 test7: offline
+ $ flux resource status
+ STATE UP NNODES NODELIST
+ avail â 2 test[0-1]
+ avail* â 6 test[2-7]
+
+If all goes well, bring up the remaining nodes:
+
+.. code-block:: console
+
+ $ sudo pdsh -a systemctl start flux
+ $ flux overlay status
+ 0 test0: full
+ ââ 1 test1: full
+ â ââ 3 test3: full
+ â ââ 4 test4: full
+ â ââ 5 test5: full
+ ââ 2 test2: full
+ ââ 6 test6: full
+ ââ 7 test7: full
+ $ flux resource status
+ STATE UP NNODES NODELIST
+ avail â 8 test[0-7]
+
+Are my queues started?
+======================
+
+If named queues are configured, they will be initially stopped, meaning
+jobs can be submitted but won't run. Enable all queues with
+
+.. code-block:: console
+
+ $ sudo flux queue start --all
+ debug: Scheduling is started
+ batch: Scheduling is started
+
+Can I run a job as a regular user?
+==================================
+
+Flux should be able to run jobs as an unprivileged user:
+
+.. code-block:: console
+
+ $ id
+ uid=1000(pi) gid=1000(pi) groups=1000(pi),27(sudo),114(netdev)
+ $ flux run -N8 id
+ uid=1000(pi) gid=1000(pi) groups=1000(pi),27(sudo),117(netdev)
+ uid=1000(pi) gid=1000(pi) groups=1000(pi),27(sudo),117(netdev)
+ uid=1000(pi) gid=1000(pi) groups=1000(pi),27(sudo),117(netdev)
+ uid=1000(pi) gid=1000(pi) groups=1000(pi),27(sudo),117(netdev)
+ uid=1000(pi) gid=1000(pi) groups=1000(pi),27(sudo),117(netdev)
+ uid=1000(pi) gid=1000(pi) groups=1000(pi),27(sudo),117(netdev)
+ uid=1000(pi) gid=1000(pi) groups=1000(pi),27(sudo),117(netdev)
+ uid=1000(pi) gid=1000(pi) groups=1000(pi),27(sudo),117(netdev)
+
+*************************
+Day to day administration
+*************************
+
+Starting Flux
+=============
+
+Systemd may be configured to start Flux automatically at boot time,
+as long as the network that carries its overlay network will be
+available at that time. Alternatively, Flux may be started manually, e.g.
+
+.. code-block:: console
+
+ $ sudo pdsh -w fluke[3,108,6-103] sudo systemctl start flux
+
+Flux brokers may be started in any order, but they won't come online
+until their parent in the tree based overlay network is available.
+
+If Flux was not shut down properly, for example if the rank 0 broker
+crashed or was killed, then Flux starts in a safe mode with job submission
+and scheduling disabled. :man1:`flux-uptime` shows the general state
+of Flux, and :man1:`flux-startlog` prints a record of Flux starts and
+stops, including any crashes.
+
+Stopping Flux
+=============
+
+The full Flux system instance may be temporarily stopped by running
+the following on the rank 0 node:
+
+.. code-block:: console
+
+ $ sudo flux shutdown
+
+This kills any running jobs, but preserves job history and the queue of
+jobs that have been submitted but have not yet allocated resources.
+This state is held in the ``content.sqlite`` that was configured above.
+See also :man1:`flux-shutdown`.
+
+.. note::
+ ``flux-shutdown --gc`` should be used from time to time to perform offline
+ KVS garbage collection. This, in conjunction with configuring inactive
+ job purging, keeps the size of the ``content.sqlite`` database in check
+ and improves Flux startup time.
+
+The brokers on other nodes will automatically shut down in response,
+then respawn, awaiting the return of the rank 0 broker.
+
+To shut down a single node running Flux, simply run
+
+.. code-block:: console
+
+ $ sudo systemctl stop flux
+
+on that node.
+
+Configuration update
+====================
+
+After changing flux broker or module specific configuration in the TOML
+files under ``/etc/flux``, the configuration may be reloaded with
+
+.. code-block:: console
+
+ $ sudo systemctl reload flux
+
+on each rank where the configuration needs to be updated. The broker will
+reread all configuration files and notify modules that configuration has
+been updated.
+
+Configuration which applies to the ``flux-imp`` or job shell will be reread
+at the time of the next job execution, since these components are executed
+at job launch.
+
+.. warning::
+ Many configuration changes have no effect until the Flux broker restarts.
+ This should be assumed unless otherwise noted. See :man5:`flux-config`
+ for more information.
+
+Viewing resource status
+=======================
+
+Flux offers two different utilities to query the current resource state.
+
+``flux resource status`` is an administrative command which lists ranks
+which are available, online, offline, excluded, or drained along with
+their corresponding node names. By default, sets which have 0 members
+are not displayed, e.g.
+
+.. code-block:: console
+
+ $ flux resource status
+ STATE UP NNODES NODELIST
+ avail â 78 fluke[6-16,19-23,25-60,62-63,68,71-73,77-78,80,82-86,88,90-91,93,95-101,103]
+ avail* â 6 fluke[17,24,61,79,92,102]
+ exclude â 3 fluke[1,3,108]
+ drained â 13 fluke[18,64-65,67,69-70,74-76,81,87,89,94]
+ drained* â 1 fluke66
+
+To list a set of states explicitly, use the ``--states`` option:
+(Run ``--states=help`` to get a list of valid states)
+
+.. code-block:: console
+
+ $ flux resource status --states=drained,exclude
+ STATE UP NNODES NODELIST
+ exclude â 3 fluke[1,3,108]
+ drained â 13 fluke[18,64-65,67,69-70,74-76,81,87,89,94]
+ drained* â 1 fluke66
+
+This option is useful to get a list of ranks or hostnames in a given
+state. For example, the following command fetches the hostlist
+for all resources configured in a Flux instance:
+
+.. code-block:: console
+
+ $ flux resource status -s all -no {nodelist}
+ fluke[1,3,6-103,108]
+
+In contrast to ``flux resource status``, the ``flux resource list``
+command lists the *scheduler*'s view of available resources. This
+command shows the free, allocated, and unavailable (down) resources,
+and includes nodes, cores, and gpus at this time:
+
+.. code-block:: console
+
+ $ flux resource list
+ STATE QUEUE PROPERTIES NNODES NCORES NODELIST
+ free batch 71 284 fluke[6-16,19-23,25-60,62-63,68,71-73,77-78,80,82-86,88,90-91,93,95]
+ free debug 6 24 fluke[96-101]
+ free debug testprop 1 4 fluke103
+ allocated 0 0
+ down batch 19 76 fluke[17-18,24,61,64-67,69-70,74-76,79,81,87,89,92,94]
+ down debug testprop 1 4 fluke102
+
+With ``--o rlist``, ``flux resource list`` will show a finer grained list
+of resources in each state, instead of a nodelist:
+
+.. code-block:: console
+
+ $ flux resource list -o rlist
+ STATE QUEUE PROPERTIES NNODES NCORES NGPUS LIST
+ free batch 71 284 0 rank[3-13,16-20,22-57,59-60,65,68-70,74-75,77,79-83,85,87-88,90,92]/core[0-3]
+ free debug 6 24 0 rank[93-98]/core[0-3]
+ free debug testprop 1 4 0 rank100/core[0-3]
+ allocated 0 0 0
+ down batch 19 76 0 rank[14-15,21,58,61-64,66-67,71-73,76,78,84,86,89,91]/core[0-3]
+ down debug testprop 1 4 0 rank99/core[0-3]
+
+
+Draining resources
+==================
+
+Resources may be temporarily removed from scheduling via the
+``flux resource drain`` command. Currently, resources may only be drained
+at the granularity of a node, represented by its hostname or broker rank,
+for example:
+
+.. code-block:: console
+
+ $ sudo flux resource drain fluke7 node is fubar
+ $ sudo flux resource drain
+ TIMESTAMP STATE RANK REASON NODELIST
+ 2020-12-16T09:00:25 draining 2 node is fubar fluke7
+
+Any work running on the "draining" node is allowed to complete normally.
+Once there is nothing running on the node its state changes to "drained":
+
+.. code-block:: console
+
+ $ sudo flux resource drain
+ TIMESTAMP STATE RANK REASON NODELIST
+ 2020-12-16T09:00:25 drained 2 node is fubar fluke7
+
+To return drained resources use ``flux resource undrain``:
+
+.. code-block:: console
+
+ $ sudo flux resource undrain fluke7
+ $ sudo flux resource drain
+ TIMESTAMP STATE RANK REASON NODELIST
+
+
+Managing the Flux queue
+=======================
+
+The queue of jobs is managed by the flux job-manager, which in turn
+makes allocation requests for jobs in priority order to the scheduler.
+This queue can be managed using the ``flux-queue`` command.
+
+.. code-block:: console
+
+ Usage: flux-queue [OPTIONS] COMMAND ARGS
+ -h, --help Display this message.
+
+ Common commands from flux-queue:
+ enable Enable job submission
+ disable Disable job submission
+ start Start scheduling
+ stop Stop scheduling
+ status Get queue status
+ drain Wait for queue to become empty.
+ idle Wait for queue to become idle.
+
+The queue may be listed with the :man1:`flux-jobs` command.
+
+Disabling job submission
+------------------------
+
+By default, the queue is *enabled*, meaning that jobs can be submitted
+into the system. To disable job submission, e..g to prepare the system
+for a shutdown, use ``flux queue disable``. To restore queue access
+use ``flux queue enable``.
+
+Stopping resource allocation
+----------------------------
+
+The queue may also be stopped with ``flux queue stop``, which disables
+further allocation requests from the job-manager to the scheduler. This
+allows jobs to be submitted, but stops new jobs from being scheduled.
+To restore scheduling use ``flux queue start``.
+
+Flux queue idle and drain
+-------------------------
+
+The ``flux queue drain`` and ``flux queue idle`` commands can be used
+to wait for the queue to enter a given state. This may be useful when
+preparing the system for a downtime.
+
+The queue is considered *drained* when there are no more active jobs.
+That is, all jobs have completed and there are no pending jobs.
+``flux queue drain`` is most useful when the queue is *disabled* .
+
+The queue is "idle" when there are no jobs in the RUN or CLEANUP state.
+In the *idle* state, jobs may still be pending. ``flux queue idle``
+is most useful when the queue is *stopped*.
+
+To query the current status of the queue use the ``flux queue status``
+command:
+
+.. code-block:: console
+
+ $ flux queue status -v
+ batch: Job submission is enabled
+ batch: Scheduling is started
+ debug: Job submission is enabled
+ debug: Scheduling is started
+ 0 alloc requests queued
+ 0 alloc requests pending to scheduler
+ 0 free requests pending to scheduler
+ 0 running jobs
+
+Managing Flux jobs
+==================
+
+Expediting/Holding jobs
+-----------------------
+
+To expedite or hold a job, set its *urgency* to the special values
+EXPEDITE or HOLD.
+
+.. code-block:: console
+
+ $ flux job urgency ÆAiVi2Sj EXPEDITE
+
+.. code-block:: console
+
+ $ flux job urgency ÆAiVi2Sj HOLD
+
+Canceling jobs
+--------------
+
+An active job may be canceled via the ``flux cancel`` command. An
+instance owner may cancel any job, while a guest may only cancel their
+own jobs.
+
+All active jobs may be canceled with ``flux cancel --user=all``.
+
+.. code-block:: console
+
+ $ flux cancel --user=all --dry-run
+ flux-cancel: Would cancel 3 jobs
+ $ flux cancel --user=all
+ flux-cancel: Canceled 3 jobs (0 errors)
+
+The set of jobs matched by the ``cancel`` command may also be restricted
+via the ``-s, --states=STATES`` and ``-u, --user=USER`` options.
+
+Software update
+===============
+
+Flux will eventually support rolling software upgrades, but prior to
+major release 1, Flux software release versions should not be assumed
+to inter-operate. Furthermore, at this early stage, Flux software
+components (e.g. ``flux-core``, ``flux-sched``, ``flux-security``,
+and ``flux-accounting``) should only only be installed in recommended
+combinations.
+
+.. note::
+ Mismatched broker versions are detected as brokers attempt to join
+ the instance. The version is currently required to match exactly.
+
+.. warning::
+ Ensure that flux is completely stopped before beginning a software
+ update. If this is not observed, Flux may fail to shut down cleanly.
+
+***************
+Troubleshooting
+***************
+
+Overlay network
+===============
+
+The tree-based overlay network interconnects brokers of the system instance.
+The current status of the overlay subtree at any rank can be shown with:
+
+.. code-block:: console
+
+ $ flux overlay status -r RANK
+
+The possible status values are:
+
+**Full**
+ Node is online and no children are in partial, offline, degraded, or lost
+ state.
+
+**Partial**
+ Node is online, and some children are in partial or offline state; no
+ children are in degraded or lost state.
+
+**Degraded**
+ Node is online, and some children are in degraded or lost state.
+
+**Lost**
+ Node has gone missing, from the parent perspective.
+
+**Offline**
+ Node has not yet joined the instance, or has been cleanly shut down.
+
+Note that the RANK argument is where the request will be sent, not necessarily
+the rank whose status is of interest. Parents track the status of their
+children, so a good approach when something is wrong to start with rank 0
+(the default). The following options can be used to ask rank 0 for a detailed
+listing:
+
+.. code-block:: console
+
+ $ flux overlay status
+ 0 fluke62: degraded
+ ââ 1 fluke63: full
+ â ââ 3 fluke65: full
+ â â ââ 7 fluke70: full
+ â â ââ 8 fluke71: full
+ â ââ 4 fluke67: full
+ â ââ 9 fluke72: full
+ â ââ 10 fluke73: full
+ ââ 2 fluke64: degraded
+ ââ 5 fluke68: full
+ â ââ 11 fluke74: full
+ â ââ 12 fluke75: full
+ ââ 6 fluke69: degraded
+ ââ 13 fluke76: full
+ ââ 14 fluke77: lost
+
+To determine if a broker is reachable from the current rank, use:
+
+.. code-block:: console
+
+ $ flux ping RANK
+
+A broker that is not responding but is not shown as lost or offline
+by ``flux overlay status`` may be forcibly detached from the overlay
+network with:
+
+.. code-block:: console
+
+ $ flux overlay disconnect RANK
+
+However, before doing that, it may be useful to see if a broker acting
+as a router to that node is actually the problem. The overlay parent
+of RANK may be listed with
+
+.. code-block:: console
+
+ $ flux overlay parentof RANK
+
+Using ``flux ping`` and ``flux overlay parentof`` iteratively, one should
+be able to isolate the problem rank.
+
+See also :man1:`flux-overlay`, :man1:`flux-ping`.
+
+Systemd journal
+===============
+
+Flux brokers log information to standard error, which is normally captured
+by the systemd journal. It may be useful to look at this log when diagnosing
+a problem on a particular node:
+
+.. code-block:: console
+
+ $ journalctl -u flux
+ Sep 14 09:53:12 sun1 systemd[1]: Starting Flux message broker...
+ Sep 14 09:53:12 sun1 systemd[1]: Started Flux message broker.
+ Sep 14 09:53:12 sun1 flux[23182]: broker.info[2]: start: none->join 0.0162958s
+ Sep 14 09:53:54 sun1 flux[23182]: broker.info[2]: parent-ready: join->init 41.8603s
+ Sep 14 09:53:54 sun1 flux[23182]: broker.info[2]: rc1.0: running /etc/flux/rc1.d/01-enclosing-instance
+ Sep 14 09:53:54 sun1 flux[23182]: broker.info[2]: rc1.0: /bin/sh -c /etc/flux/rc1 Exited (rc=0) 0.4s
+ Sep 14 09:53:54 sun1 flux[23182]: broker.info[2]: rc1-success: init->quorum 0.414207s
+ Sep 14 09:53:54 sun1 flux[23182]: broker.info[2]: quorum-full: quorum->run 9.3847e-05s
+
+Broker log buffer
+=================
+
+The rank 0 broker accumulates log information for the full instance in a
+circular buffer. For some problems, it may be useful to view this log:
+
+.. code-block:: console
+
+ $ sudo flux dmesg -H |tail
+
+ [May02 14:51] sched-fluxion-qmanager[0]: feasibility_request_cb: feasibility succeeded
+ [ +0.039371] sched-fluxion-qmanager[0]: alloc success (queue=debug id=184120855100391424)
+ [ +0.816587] sched-fluxion-qmanager[0]: feasibility_request_cb: feasibility succeeded
+ [ +0.857458] sched-fluxion-qmanager[0]: alloc success (queue=debug id=184120868807376896)
+ [ +1.364430] sched-fluxion-qmanager[0]: feasibility_request_cb: feasibility succeeded
+ [ +6.361275] job-ingest[0]: job-frobnicator[0]: inactivity timeout
+ [ +6.367837] job-ingest[0]: job-validator[0]: inactivity timeout
+ [ +24.778929] job-exec[0]: exec aborted: id=184120855100391424
+ [ +24.779019] job-exec[0]: exec_kill: 184120855100391424: signal 15
+ [ +24.779557] job-exec[0]: exec aborted: id=184120868807376896
+ [ +24.779632] job-exec[0]: exec_kill: 184120868807376896: signal 15
+ [ +24.779910] sched-fluxion-qmanager[0]: alloc canceled (id=184120878001291264 queue=debug)
+ [ +25.155578] job-list[0]: purged 1 inactive jobs
+ [ +25.162650] job-manager[0]: purged 1 inactive jobs
+ [ +25.512050] sched-fluxion-qmanager[0]: free succeeded (queue=debug id=184120855100391424)
+ [ +25.647542] sched-fluxion-qmanager[0]: free succeeded (queue=debug id=184120868807376896)
+ [ +27.155103] job-list[0]: purged 2 inactive jobs
+ [ +27.159820] job-manager[0]: purged 2 inactive jobs
diff --git a/doc/guide/broker.rst b/doc/guide/broker.rst
new file mode 100644
index 000000000000..6e7d711522b1
--- /dev/null
+++ b/doc/guide/broker.rst
@@ -0,0 +1,506 @@
+.. _broker:
+
+######
+Broker
+######
+
+The :man1:`flux-broker` provides an overlay network and a framework for
+implementing distributed, message-based services.
+
+.. note::
+ This document is incomplete. Please open an issue on
+ `github `_
+ if you have a need for broker information that is missing and we will
+ do our best to answer questions and fill gaps in the documentation.
+
+
+*************************
+Broker Bootstrap Sequence
+*************************
+
+Each broker executes a bootstrap sequence to
+
+1. get the size of the Flux instance
+2. get its rank within the Flux instance
+3. get its level within the hierarchy of Flux instances
+4. get the mapping of broker ranks to nodes
+5. compute the broker ranks of its peers (TBON parent and children)
+6. get URI(s) of peers
+7. get public key(s) of peers to initialize secure communication
+
+An instance bootstraps using one of two mechanisms: PMI or Config File.
+
+PMI
+===
+
+When Flux is launched by Flux, by another resource manager, or as a
+standalone test instance, PMI is used for bootstrap.
+
+The broker PMI client uses a simple subset of PMI capabilities, abstracted for
+different server implementations in the plugin-based UPMI subsystem defined
+in `upmi.h 0, entering CLEANUP does not launch a process,
+and immediately generates an event.
+
+.. image:: images/states.png
+ :scale: 100 %
+ :alt: broker state machine
+
+.. list-table::
+ :header-rows: 1
+
+ * - abbrev
+ - state
+ - action when transitioning into state
+
+ * - J
+ - JOIN
+ - wait for parent to enter QUORUM state
+
+ * - 1
+ - INIT
+ - run rc1 script
+
+ * - B
+ - QUORUM
+ - wait for quorum of brokers to reach this point
+
+ * - 2
+ - RUN
+ - run initial program (rank 0)
+
+ * - C
+ - CLEANUP
+ - run cleanup (rank 0)
+
+ * - S
+ - SHUTDOWN
+ - wait for children to finalize and exit
+
+ * - 3
+ - FINALIZE
+ - run rc3 script
+
+ * - G
+ - GOODBYE
+ - wait for flux-shutdown, if any
+
+ * - E
+ - EXIT
+ - exit broker
+
+Normal State Transitions
+========================
+
+It may be helpful to walk through the state transitions that occur when
+a Flux instance runs to completion without encountering exceptional conditions.
+
+.. image:: images/states_norm.png
+ :scale: 100 %
+ :alt: broker state machine
+
+green = common path; blue = rank 0 deviation from common path; red = leaf
+node deviation from common path
+
+startup
+-------
+
+The broker ranks > 0 wait for the parent to enter QUORUM state (*parent-ready*)
+then enters INIT state. Rank 0 immediately enters INIT (*parent-none*).
+Upon entering INIT, the rc1 script is executed, then on completion, QUORUM
+state is entered (*rc1-success*). Because each TBON tree level waits for the
+upstream level to enter QUORUM state before entering INIT state, rc1 executes
+in upstream-to-downstream order. This ensures upstream service leaders are
+loaded before downstream followers.
+
+Once a configured number of brokers have reached QUORUM state (default all),
+RUN state is entered (*quorum-full*). Rank 0 then starts the initial program.
+
+All ranks remain in RUN state until the initial program completes.
+
+shutdown
+--------
+
+When the initial program completes, rank 0 transitions to CLEANUP state
+(*rc2-success*) and runs any cleanup script(s). Cleanups execute while the
+other broker ranks remain in RUN state. Upon completion of cleanups, rank 0
+enters SHUTDOWN state (*cleanup-success*).
+
+The broker ranks > 0 monitor parent state transitions. The parent
+transitioning to SHUTDOWN causes a transition from RUN to CLEANUP
+(*shutdown*). They immediately transition through CLEANUP (*cleanup-none*)
+to SHUTDOWN state.
+
+All brokers with children remain in SHUTDOWN until their children disconnect
+(*children-complete*). If they have no children (leaf node), they transition
+out of SHUTDOWN immediately (*children-none*). The next state is FINALIZE,
+where the rc3 script is executed. Upon completion of rc3 (*rc3-success*),
+brokers transition to EXIT and disconnect from the parent.
+
+Because each TBON tree level waits for the downstream level to disconnect
+before entering FINALIZE state, rc3 executes in downstream-to-upstream order.
+This ensures downstream service followers are unloaded before upstream leaders.
+
+The rank 0 broker is the last to exit.
+
+variation: no rc2 script (initial program)
+------------------------------------------
+
+A system instance does not define an initial program. Brokers transition to
+RUN state as above, and remain there until the *shutdown* event is
+posted. That may occur if:
+- the broker receives a signal
+- the broker's TBON parent enters SHUTDOWN state
+- (rank 0 only) :man1:`flux-shutdown` requests instance shutdown
+
+variation: no rc1, rc3, or cleanup scripts
+------------------------------------------
+
+In test sometimes we eliminate the rc1, cleanup, and/or rc3 scripts to simplify
+or speed up a test environment. In these cases, entry into INIT, CLEANUP,
+and FINALIZE states generates a *rc1-none*, *cleanup-none*, or *rc3-none*
+event, which causes an immediate transition to the next state.
+
+Events
+======
+
+.. list-table::
+ :header-rows: 1
+
+ * - event
+ - description
+
+ * - parent-ready
+ - parent has entered BARRIER state
+
+ * - parent-none
+ - this broker has no parent
+
+ * - parent-fail
+ - parent has ended communication with this broker
+
+ * - parent-timeout
+ - parent has not responded within timeout period
+
+ * - rc1-none
+ - rc1 script is defined on this broker
+
+ * - rc1-success
+ - rc1 script completed successfully
+
+ * - rc1-fail
+ - rc1 script completed with errors
+
+ * - quorum-full
+ - configured quorum of brokers reached
+
+ * - quorum-timeout
+ - configured quorum not reached within timeout period
+
+ * - rc2-none
+ - no rc2 script (initial program) is defined on this broker
+
+ * - rc2-success
+ - rc2 script completed successfully
+
+ * - rc2-fail
+ - rc2 script completed with errors
+
+ * - shutdown
+ - broker received an external cue to begin shutting down
+
+ * - signal-abort
+ - broker received terminating signal
+
+ * - cleanup-none
+ - no cleanup script is defined on this broker
+
+ * - cleanup-success
+ - cleanup script completed successfully
+
+ * - cleanup-fail
+ - cleanup script completed with errors
+
+ * - children-complete
+ - all children have disconnected from this broker
+
+ * - children-none
+ - this broker has no children
+
+ * - children-timeout
+ - children did not disconnected within timeout period
+
+ * - rc3-none
+ - no rc3 script is defined on this broker
+
+ * - rc3-success
+ - rc3 script completed successfully
+
+ * - rc3-fail
+ - rc3 script completed with errors
+
+ * - goodbye
+ - any flux-shutdown commands have completed
+
+**************************
+System Instance Resiliency
+**************************
+
+The Flux system instance has to deal with the usual challenges faced by cluster
+system software, such as node crashes and network outages. Although Flux's
+design attempts to meet these challenges with minimal human intervention and
+lost work, there are caveats that need to be understood by Flux developers.
+This page describes Flux's current design for resiliency.
+
+NOTE: some of this is aspirational at the time of this writing, for our L2
+resiliency planning goal to be demonstrated in early 2022.
+
+Disordered bring-up
+===================
+
+The broker state machine ensures that a starting broker pauses until its TBON
+parent completes the rc1 script before starting its own rc1 script, so that
+upstream services are online before downstream ones start. As a result, it
+is feasible to configure Flux to start automatically, then power on the entire
+cluster at once and let Flux sort itself out.
+
+If some nodes take longer to start up, or don't start at all, then those nodes
+and their TBON children, if any, will remain offline until they do start.
+The TBON has a fixed topology determined by configuration, and brokers do not
+adapt to route around down nodes. In addition, Flux must be completely stopped
+to alter the topology configuration - it cannot be changed on the fly.
+
+See the `Flux Administrator's Guide `_
+for a discussion on draining nodes and excluding nodes from scheduling via
+configuration. Scheduling is somewhat orthogonal to this topic.
+
+Subtree shut down
+=================
+
+Flux is stopped administratively with `systemctl stop flux`. This is may
+be run on any broker, and will affect the broker's TBON subtree. If run on
+the rank 0 broker, the entire Flux instance is shut down.
+
+Upon receiving SIGTERM from systemd, the broker informs its TBON children that
+it is shutting down, and waits for them to complete rc3 in leaves-to-root
+order, thus ensuring that the instance captures any state held on those
+brokers, such as KVS content.
+
+A broker that is cleanly shut down withdraws itself as a peer from its TBON
+parent. Future RPCs to the down broker automatically receive an EHOSTUNREACH
+error response.
+
+Node crash
+==========
+
+If a node crashes without shutting down its flux broker, state held by that
+broker and its TBON subtree is lost if it was not saved to its TBON parent.
+
+The TBON parent of the lost node detects that its child has stopped sending
+messages. The parent marks the child lost and future RPCs directed to
+(or through) the crashed node receive an EHOSTUNREACH error response. In
+addition, RPCs are tracked at the broker overlay level, and any requests that
+were directed to (or through) the lost node that are unterminated, as
+defined by :doc:`RFC 6 ` receive an EHOSTUNREACH error response.
+
+The TBON children of the lost node similarly detect the lack of parent
+messages. The child marks the parent offline and future RPCs, as well as
+existing unterminated RPCs to that node receive an EHOSTUNREACH error response.
+These nodes then proceed as though they were shut down, however since they are
+cut off from upstream, any RPCs executed in rc3 to save state will fail
+immediately. Effectively a *subtree panic* results and data may be lost.
+
+Node returning to Service
+=========================
+
+When a lost node comes back up, or when an administratively shut down node
+is restarted with
+
+.. code-block:: console
+
+ systemctl start flux
+
+the freshly started broker attempts to join the instance via its TBON parent,
+just as if it were joining for the first time, and carrying no state from
+the previous incarnation.
+
+The broker peer is identified for response routing purposes by its UUID, which
+changes upon restart. In-flight responses directed to (or through) the
+old UUID are dropped. This is desirable behavior because matchtags from the
+previous broker incarnation(s) might become confused with matchtags from the
+current one, and the old responses are answering requests that the current
+broker didn't send.
+
+:linux:man1:`systemd` is configured to aggressively restart brokers that stop
+on their own, so TBON children of the returning broker should also be
+attempting to join the instance and may do so once the returning broker has
+completed the rc1 script.
+
+Network outage
+==============
+
+Network outages that persist long enough are promoted to hard failures.
+
+Case 1: A TBON parent marks its child lost due to a temporary network
+interruption, and the child has not yet marked the parent lost when
+communication is restored. In this case, the parent sees messages from the
+lost UUID, and sends a kiss of death message to the child, causing a subtree
+panic at the child. The subtree restarts and rejoins the instance.
+
+Case 2: The TBON child marks its parent lost due to a temporary network
+interruption, and the parent has not yet marked the child lost when
+communication is restored. Assuming the child subtree has restarted,
+the child introduces itself to the parent with a new UUID. Before allowing
+the child to join, it marks the old UUID lost and fails unterminated RPCs
+as described above. It then accepts the child's introduction and allows
+the subtree to join.
+
+Diagnostic: subtree health check
+================================
+
+Each broker maintains a subtree health state that depends on the health
+state reported by its TBON children. The states are as follows:
+
+.. list-table::
+ :header-rows: 1
+
+ * - name
+ - description
+
+ * - full
+ - online and no children partial/offline/degraded/lost
+
+ * - partial
+ - online, some children partial/offline; no children degraded/lost
+
+ * - degraded
+ - online, some children degraded/lost
+
+ * - lost
+ - gone missing (according to parent)
+
+ * - offline
+ - not yet seen, or cleanly shut down (according to parent)
+
+A user may quickly assess the overall health of the overlay network by
+requesting the subtree health at rank 0. If the state is reported as
+*partial* or *degraded*, then the TBON may be probed further for details
+using the following algorithm:
+
+1. Request state of TBON children from target rank
+2. List TBON children in *lost* or *offline* state
+3. For each child in *partial* or *degraded* state, apply this algorithm
+ on child rank
diff --git a/doc/guide/build.rst b/doc/guide/build.rst
new file mode 100644
index 000000000000..558b42decc1e
--- /dev/null
+++ b/doc/guide/build.rst
@@ -0,0 +1,130 @@
+Building Releases
+=================
+
+Version Numbering
+-----------------
+
+Flux-core releases are numbered with
+`Semantic Versioning `_, where MAJOR.MINOR.PATCH release
+numbers communicate that:
+
+- major releases may break API
+
+- minor releases add functionality in a backward compatible manner
+
+- patch releases make backward compatible bug fixes
+
+At this time, the project is at major version zero, indicating interfaces
+are not yet stable. That said, flux-core developers try to minimize
+disruption to early adopters and announce any necessary breaking changes
+in the release notes.
+
+Obtaining Releases
+------------------
+
+Tarballs and release notes are available on the
+`Github releases page `_.
+
+Releases for all Flux framework projects are also announced on the
+`Flux Framework releases page `_.
+
+Installing Dependencies
+-----------------------
+
+Several external software packages are prerequisites for building Flux.
+Scripts that install these packages for debian and redhat based distros are
+located in the flux-core source tree ``scripts`` sub-directory.
+
+The following packages are optional and may be omitted if you do not require
+the associated functionality:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Package
+ - Functionality
+
+ * - `flux-security `_
+ - Launching work as multiple users.
+
+ For example when Flux is to be the native resource manager on a cluster.
+
+ * - Sphinx
+ - Building man pages and documentation
+
+ * - MPI
+ - Test only: sanity tests that Flux can launch MPI programs
+
+ * - valgrind
+ - Test only: checks for memory errors
+
+Configuring and Building a Release
+----------------------------------
+
+flux-core uses GNU autotools internally, so it supports the usual
+`Use Cases for the GNU Build System `_. A standard build follows this pattern:
+
+.. code-block:: console
+
+ $ tar xzf flux-core-X.Y.Z.tar.gz
+ $ cd flux-core-X.Y.Z
+ $ ./configure --with-flux-security
+ $ make
+ $ make check
+ $ make install
+
+Configure *should* abort if any required build dependencies are missing or
+insufficient. Configure options options may be listed with ``./configure
+--help``.
+
+``make -j N`` may be used to speed up the build and check targets by
+increasing parallelism.
+
+All checks are expected to pass, although some timing related test defects
+may cause tests to sporadically fail on slow systems or when run with too much
+parallelism. ``make recheck`` re-runs any failing checks.
+
+Packages
+--------
+
+RPM packages for TOSS 4 (RHEL 8 based) are produced by the TOSS build system
+and can be made available externally on request. When requested, these are
+manually added to the release assets on github.
+
+deb packages for Debian or Ubuntu can be built from a release tarball with
+``make deb``, producing debs in the ``debbuild`` sub-directory. This target
+is used by some Flux team members to build packages for test clusters running
+the `Raspberry Pi OS `_ (Debian/GNU 11).
+
+Docker Images
+-------------
+
+Docker images for tagged releases as well as a current development snapshot
+are available in the `fluxrm/flux-core Dockerhub
+`_. For example, the following
+downloads a debian bookworm image containing flux-core 0.54.0 and starts a
+flux instance within it:
+
+.. code-block:: console
+
+ $ docker pull fluxrm/flux-core:bookworm-v0.54.0-amd64
+ $ docker run -ti fluxrm/flux-core:bookworm-v0.54.0-amd64
+ Æ(s=1,d=0) fluxuser@080d84548cc4:~$
+
+Spack
+-----
+
+Flux-core and its dependencies can also be built using `spack
+`_, for example:
+
+.. code-block:: console
+
+ $ git clone --depth=100 https://github.com/spack/spack.git
+ $ cd spack
+ $ . share/spack/setup-env.sh
+ $ spack install flux-core@0.54.0 %gcc@11.4.0
+ $ spack find flux-core
+ -- linux-ubuntu22.04-zen2 / gcc@11.4.0 --------------------------
+ flux-core@0.54.0
+ ==> 1 installed package
+ $ spack load flux-core
diff --git a/doc/guide/debug.rst b/doc/guide/debug.rst
new file mode 100644
index 000000000000..b2dad8e6fb18
--- /dev/null
+++ b/doc/guide/debug.rst
@@ -0,0 +1,62 @@
+.. _debug:
+
+###############
+Debugging Notes
+###############
+
+***********************
+source tree executables
+***********************
+
+`libtool `_ is
+in use, so :option:`libtool e` trickery is needed to launch a tool against
+an actual compiled executable. Command front ends further complicate this.
+
+.. note::
+ :option:`libtool e` is shorthand for :option:`libtool --mode=execute`.
+
+Example: run a built-in sub-command under GDB
+
+.. code-block::
+
+ $ libtool e gdb --ex run --args src/cmd/flux version
+
+Example: run an external sub-command under GDB
+
+.. code-block::
+
+ $ src/cmd/flux /usr/bin/libtool e gdb --ex run --args src/cmd/flux-keygen
+
+Example: run the broker under GDB
+
+.. code-block::
+
+ $ src/cmd/flux start --wrap=libtool,e,gdb,--ex,run
+
+Example: run the broker under valgrind
+
+.. code-block::
+
+ $ src/cmd/flux start --wrap=libtool,e,valgrind
+
+***************
+message tracing
+***************
+
+Example: trace messages sent/received by a command
+
+.. code-block::
+
+ $ FLUX_HANDLE_TRACE=t flux kvs get foo
+
+Example: trace messages sent/received by two broker modules
+
+.. code-block::
+
+ $ flux module trace --full content kvs
+
+Example: trace messages sent/received by this broker on the overlay network
+
+.. code-block::
+
+ $ flux overlay trace --full
diff --git a/doc/guide/glossary.rst b/doc/guide/glossary.rst
new file mode 100644
index 000000000000..cd518047055e
--- /dev/null
+++ b/doc/guide/glossary.rst
@@ -0,0 +1,112 @@
+Glossary
+========
+
+Here we define Flux-specific and general HPC and workload management terms
+used in our documentation that may not be familiar to all readers.
+
+.. glossary::
+
+ enclosing instance
+ The Flux instance that a process naturally interacts with. It is
+ the instance referred to by the :envvar:`FLUX_URI` environment variable,
+ or if that is not set, it is the :term:`system instance`.
+
+ expedited
+ A job is said to be expedited if its :term:`urgency` is set to the
+ maximum value of 31. An expedited job's :term:`priority` is always set
+ to the maximum value.
+
+ FSD
+ A common string representation of time duration, defined by
+ :doc:`rfc:spec_23`. Example: ``2.5h``.
+
+ guest
+ A Flux user that is not the :term:`instance owner`. Guests are only
+ allowed to run in a Flux instance configured for multi-user support,
+ normally a :term:`system instance`.
+
+ held
+ A job is said to be held if its :term:`urgency` is set to zero. This
+ prevents it from being considered for scheduling until the urgency is
+ raised.
+
+ hostlist
+ A compact string representation of a list of hostnames, defined by
+ :doc:`rfc:spec_29`. Example: ``fluke[0-127,130]``.
+
+ idset
+ A compact string representation of a set of non-negative integers,
+ defined by :doc:`rfc:spec_22`. Example: ``2,4,6,1-100``.
+
+ IMP
+ The Independent Minister of Privilege. The simple setuid root component
+ of Flux, from the flux-security project, that allows an
+ :term:`instance owner` to perform a limited set of tasks on behalf of a
+ :term:`guest` user in a multi-user Flux instance.
+
+ initial program
+ A user-defined program, such as a batch script, launched on the first
+ node of a Flux instance. Its purpose is to launch and monitor a
+ workload. Once it is complete, the instance exits.
+
+ instance owner
+ The user that started the Flux instance. The instance owner has control
+ over all aspects of the Flux instance's operation.
+
+ job
+ The smallest unit of work that can be allocated resources and run by Flux.
+ A job can be a Flux instance which in turn can run more jobs.
+
+ jobspec
+ The JSON or YAML object representing a Flux job request, defined by
+ :doc:`rfc:spec_14` (the general specification) and :doc:`rfc:spec_25`
+ (the current version). It includes the abstract resource requirements
+ of the job and instructions for job execution.
+
+ priority
+ The order in which the scheduler considers jobs. By default, priority
+ is derived from the :term:`urgency` and submit time, but a priority plugin
+ can be used to override this calculation.
+
+ R
+ The JSON object used by Flux to represent a concrete resource set.
+ See :doc:`rfc:spec_20`.
+
+ resource inventory
+ The concrete set of resources managed by a given Flux instance.
+
+ scheduler
+ The Flux component that fulfills resource allocation requests from the
+ :term:`resource inventory`. Abstract resource requirements are extracted
+ from the user-provided :term:`jobspec`, and fulfilled with a resource set
+ expressed as :term:`R`. In addition to fitting concrete resources to
+ abstract requests, the scheduler must balance goals such as fairness
+ and resource utilization when it decides upon a schedule for fulfilling
+ competing requests.
+
+ slot
+ The abstract resource requirements of one task.
+
+ step
+ In other workload managers, a job step is a unit of work within a job.
+ Flux, which has a robust recursive definition of a :term:`job`, does not
+ use this term.
+
+ system instance
+ A multi-user Flux instance running as the primary resource manager
+ on a cluster. The system instance typically runs as an unprivileged
+ system user like ``flux``, is started by :linux:man1:`systemd`, and
+ allows :term:`guest` users to run jobs.
+
+ taskmap
+ A compact mapping between job task ranks and node IDs, defined by
+ :doc:`rfc:spec_34`.
+
+ TBON
+ Tree based overlay network. Flux brokers are interconnected with one.
+
+ urgency
+ A job attribute that the user sets to indicate how urgent the work is.
+ The range is 0 to 31, with a default value of 16. Urgency is defined
+ by :doc:`rfc:spec_30`.
+
diff --git a/doc/guide/images/Frog-1.svg b/doc/guide/images/Frog-1.svg
new file mode 100644
index 000000000000..ff7b4a7fbebb
--- /dev/null
+++ b/doc/guide/images/Frog-1.svg
@@ -0,0 +1,91 @@
+
+
+
+
\ No newline at end of file
diff --git a/doc/guide/images/adminarch.dia b/doc/guide/images/adminarch.dia
new file mode 100644
index 000000000000..05f8be68c16f
Binary files /dev/null and b/doc/guide/images/adminarch.dia differ
diff --git a/doc/guide/images/adminarch.png b/doc/guide/images/adminarch.png
new file mode 100644
index 000000000000..25f55105aafc
Binary files /dev/null and b/doc/guide/images/adminarch.png differ
diff --git a/doc/guide/images/fox-standing.svg b/doc/guide/images/fox-standing.svg
new file mode 100644
index 000000000000..7d5d064b589e
--- /dev/null
+++ b/doc/guide/images/fox-standing.svg
@@ -0,0 +1,80 @@
+
+
+
\ No newline at end of file
diff --git a/doc/guide/images/lgplv3-147x51.png b/doc/guide/images/lgplv3-147x51.png
new file mode 100644
index 000000000000..012f011becd9
Binary files /dev/null and b/doc/guide/images/lgplv3-147x51.png differ
diff --git a/doc/guide/images/states.dot b/doc/guide/images/states.dot
new file mode 100644
index 000000000000..1688df302f7e
--- /dev/null
+++ b/doc/guide/images/states.dot
@@ -0,0 +1,36 @@
+// Usage: dot -Tpng file.dot -o file.png
+
+digraph finite_state_machine {
+ rankdir=LR;
+ size="8,5"
+
+ node [shape = point ]; N
+ node [shape = doublecircle ]; E
+
+ node [shape = circle];
+ N -> J;
+ J -> 1 [ label = "parent-ready" ];
+ J -> 1 [ label = "parent-none" ];
+ J -> S [ label = "parent-fail" ];
+ J -> S [ label = "parent-timeout" ];
+ 1 -> Q [ label = "rc1-none" ];
+ 1 -> Q [ label = "rc1-success" ];
+ 1 -> S [ label = "rc1-fail" ];
+ Q -> 2 [ label = "quorum-full" ];
+ Q -> S [ label = "quorum-timeout" ];
+ 2 -> 2 [ label = "rc2-none" ];
+ 2 -> C [ label = "rc2-success" ];
+ 2 -> C [ label = "rc2-fail" ];
+ 2 -> C [ label = "shutdown" ];
+ 2 -> C [ label = "signal-abort" ];
+ C -> S [ label = "cleanup-none" ];
+ C -> S [ label = "cleanup-success" ];
+ C -> S [ label = "cleanup-fail" ];
+ S -> 3 [ label = "children-complete" ];
+ S -> 3 [ label = "children-none" ];
+ S -> 3 [ label = "children-timeout" ];
+ 3 -> G [ label = "goodbye" ];
+ G -> E [ label = "rc3-none" ];
+ G -> E [ label = "rc3-success" ];
+ G -> E [ label = "rc3-fail" ];
+}
diff --git a/doc/guide/images/states.png b/doc/guide/images/states.png
new file mode 100644
index 000000000000..28a9e115c51d
Binary files /dev/null and b/doc/guide/images/states.png differ
diff --git a/doc/guide/images/states_norm.dot b/doc/guide/images/states_norm.dot
new file mode 100644
index 000000000000..146898f31c3b
--- /dev/null
+++ b/doc/guide/images/states_norm.dot
@@ -0,0 +1,36 @@
+// Usage: dot -Tpng file.dot -o file.png
+
+digraph finite_state_machine {
+ rankdir=LR;
+ size="8,5"
+
+ node [shape = point ]; N
+ node [shape = doublecircle ]; E
+
+ node [shape = circle];
+ N -> J [ color= "green" ];
+ J -> 1 [ label = "parent-ready", color = "green" ];
+ J -> 1 [ label = "parent-none", color = "blue" ];
+ J -> S [ label = "parent-fail" ];
+ J -> S [ label = "parent-timeout" ];
+ 1 -> Q [ label = "rc1-none" ];
+ 1 -> Q [ label = "rc1-success", color = "green" ];
+ Q -> 2 [ label = "quorum-full", color = "green" ];
+ Q -> S [ label = "quorum-timeout" ];
+ 1 -> S [ label = "rc1-fail" ];
+ 2 -> 2 [ label = "rc2-none", color = "green" ];
+ 2 -> C [ label = "rc2-success", color = "blue" ];
+ 2 -> C [ label = "rc2-fail" ];
+ 2 -> C [ label = "shutdown", color = "green" ];
+ 2 -> C [ label = "signal-abort" ];
+ C -> S [ label = "cleanup-none", color = "green" ];
+ C -> S [ label = "cleanup-success", color = "blue" ];
+ C -> S [ label = "cleanup-fail" ];
+ S -> 3 [ label = "children-complete", color = "green" ];
+ S -> 3 [ label = "children-none", color = "red" ];
+ S -> 3 [ label = "children-timeout" ];
+ 3 -> G [ label = "goodbye" ];
+ G -> E [ label = "rc3-none" ];
+ G -> E [ label = "rc3-success", color = "green" ];
+ G -> E [ label = "rc3-fail" ];
+}
diff --git a/doc/guide/images/states_norm.png b/doc/guide/images/states_norm.png
new file mode 100644
index 000000000000..d9e4ffd52fc5
Binary files /dev/null and b/doc/guide/images/states_norm.png differ
diff --git a/doc/guide/interact.rst b/doc/guide/interact.rst
new file mode 100644
index 000000000000..adac43e9ff3e
--- /dev/null
+++ b/doc/guide/interact.rst
@@ -0,0 +1,354 @@
+Interacting with Flux
+=====================
+
+.. _command_summary:
+
+Command Summary
+---------------
+
+Here is an abbreviated list of Flux commands, to get you started while exploring
+Flux. If commands fail to connect to a Flux instance, refer to
+:ref:`connect_to_flux` below.
+
+To learn more, help is available within most commands, and many have
+:ref:`Manual Pages `.
+
+.. list-table::
+ :header-rows: 1
+
+ * - Example
+ - Description
+
+ * - :command:`flux help`
+
+ :command:`flux help run`
+
+ :command:`flux run --help`
+
+ :command:`flux job kill --help`
+
+ - Print a brief command summary.
+
+ Display :man1:`flux-run`.
+
+ Summarize run options.
+
+ List usage and options for :option:`flux job kill` sub-command.
+
+ * - :command:`flux start -s16`
+
+ - Start a test instance that mocks 16 nodes. See :man1:`flux-start`.
+
+ * - :command:`flux version`
+
+ :command:`flux uptime`
+
+ - Print the Flux version. See :man1:`flux-version`.
+
+ Show brief Flux instance info. See :man1:`flux-uptime`.
+
+ * - :command:`flux ping 15`
+
+ :command:`flux exec -x 0 cmd`
+
+ - Bounce a message off broker rank 15. See :man1:`flux-ping`.
+
+ Run cmd on all ranks except rank 0. Not a job. See :man1:`flux-exec`.
+
+ * - :command:`flux resource info`
+
+ :command:`flux resource list`
+
+ :command:`flux resource status`
+
+ - Show a single line summary of scheduler view of resources.
+
+ Show longer scheduler view of resources.
+
+ Show system view of resources. See :man1:`flux-resource`.
+
+ * - :command:`flux run sleep 5`
+
+ :command:`flux run -N8 -n16 hostname`
+
+ :command:`flux run -n64 hostname`
+
+ - Run a job with 1 :linux:man1:`sleep` command. Blocks until done.
+
+ Run a job with 16 :linux:man1:`hostname` commands, two per node.
+
+ Run a job with 64 tasks with 1 cpu per task. See :man1:`flux-run`.
+
+ * - :command:`flux submit -n64 -c2 hostname`
+
+ :command:`flux submit --cc 1-5 sleep 30`
+
+ :command:`flux watch --all`
+
+ - Submit a job with 64 tasks, 2 cpus per task. See :man1:`flux-submit`.
+
+ Submit 5 jobs, each consisting of one :linux:man1:`sleep` task.
+
+ Watch all job output and wait for completion. See :man1:`flux-watch`.
+
+ * - :command:`flux alloc -N4`
+
+ :command:`flux bulksubmit sleep {} ::: 8 9`
+
+ :command:`flux top`
+
+ - Start an interactive 4 node instance. See :man1:`flux-alloc`.
+
+ Submit 2 jobs that sleep different times. See :man1:`flux-bulksubmit`.
+
+ View the progress of running jobs. See :man1:`flux-top`.
+
+ * - :command:`flux batch -N4 script.sh`
+
+ :command:`flux batch -N1 --wrap sleep 60`
+
+ :command:`flux pstree`
+
+ - Submit job to run :command:`script.sh` in a 4 node instance.
+
+ Submit job to run :linux:man1:`sleep` in a 1 node instance. See :man1:`flux-batch`.
+
+ Display tree of running jobs by name. See :man1:`flux-pstree`.
+
+ * - :command:`flux jobs -A`
+
+ :command:`flux jobs -a`
+
+ :command:`flux jobs -o endreason ÆuAsjAo`
+
+ :command:`flux job last`
+
+ - List active jobs for all users. See :man1:`flux-jobs`.
+
+ List all my jobs (inactive too).
+
+ Show info about the specified job including why it ended.
+
+ Print my most recently submitted jobid. See :man1:`flux-job`.
+
+ * - :command:`flux cancel ÆuAsjAo`
+
+ :command:`flux job kill -s HUP ÆuAsjAo`
+
+ :command:`flux pgrep -f pending .`
+
+ :command:`flux pkill sl..p`
+
+ - Cancel specified job. See :man1:`flux-cancel`.
+
+ Send specified job a SIGHUP. See :man1:`flux-job`.
+
+ List ids of all pending jobs. See :man1:`flux-pgrep`.
+
+ Cancel all jobs named sleep or slurp. See :man1:`flux-pkill`.
+
+.. _connect_to_flux:
+
+Connecting to Flux
+------------------
+
+Flux commands need a Flux instance to talk to. Which one? Remember that batch
+jobs are Flux instances, allocations are Flux instances, and Slurm jobs can
+even be Flux instances. Complicating matters, Flux instances can be launched
+recursively.
+
+local URI
+^^^^^^^^^
+
+Each instance, or more properly each Flux broker within an instance, can
+be contacted via a unique local URI. The URI corresponds to a UNIX domain
+socket and looks something like::
+
+ local:///tmp/flux-lMDa6Z/local-0
+
+In the :term:`initial program` (batch script, interactive alloc shell, or
+whatever), the FLUX_URI environment variable is set to the local URI of the rank
+0 broker. Flux commands in the initial program, which also runs on rank 0,
+read FLUX_URI and reference the instance that started them.
+
+When running outside of an instance, FLUX_URI will not be set. In this case,
+commands fall back to the compiled-in URI of the Flux :term:`system instance`.
+When there isn't a broker of the system instance running on the local node,
+commands fail with an error like::
+
+ ERROR: Unable to connect to Flux: broker socket /run/flux/local was not found
+
+remote URI
+^^^^^^^^^^
+
+A Flux instance also has a remote URI that looks like::
+
+ ssh://test3/tmp/flux-lMDacZ/local-0
+
+This is the local URI above with the scheme changed to "ssh" and the hostname
+"test3" prepended to the path. Given a job ID, :man1:`flux-uri` can look up
+the remote URI:
+
+.. code-block:: console
+
+ $ flux batch -N2 --wrap sleep 120
+ ÆcbUvuHDCiB
+ $ flux uri ÆcbUvuHDCiB
+ ssh://test3/tmp/flux-gMypIR/local-0
+ $
+
+Which can be used as follows:
+
+.. _sleep_example:
+
+.. code-block:: console
+
+ $ flux batch -N2 --wrap sleep 120
+ ÆcbUvuHDCiB
+ $ FLUX_URI=$(flux uri $(flux job last)) flux submit --cc 1-5 -N2 sleep 60
+ Æ3croSDd
+ Æ3ctHRVy
+ Æ3ctHRVz
+ Æ3cumQnK
+ Æ3cwFQ4f
+ $ FLUX_URI=$(flux uri $(flux job last)) flux jobs
+ JOBID USER NAME ST NTASKS NNODES TIME INFO
+ Æ3ctHRVy alice sleep S 2 2 -
+ Æ3ctHRVz alice sleep S 2 2 -
+ Æ3cumQnK alice sleep S 2 2 -
+ Æ3cwFQ4f alice sleep S 2 2 -
+ Æ3croSDd alice sleep R 2 2 6.593s test[3-4]
+
+That started a batch job with a lifetime of 120s, then submitted 5 "sleep 60"
+jobs to it, then listed the batch job's active jobs.
+
+parent URI
+^^^^^^^^^^
+
+Sometimes it's handy to direct a Flux command at the enclosing or parent
+instance of the current Flux instance. The :man1:`flux` command driver has
+a ``--parent`` option which alters FLUX_URI to refer to the enclosing instance
+in its sub-command's environment.
+
+How would a batch job submit a cleanup job to run upon its completion? The
+cleanup job would be submitted to the enclosing instance rather than the
+batch instance. The batch script might do this:
+
+.. code-block:: sh
+
+ #!/bin/sh
+ batch_jobid=$(flux getattr jobid)
+ flux --parent submit --dependency afterany:$batch_jobid cleanup.sh
+
+URI resolver
+^^^^^^^^^^^^
+
+:man1:`flux-uri` and some Flux commands employ an internal URI resolver class
+that can use various tricks to find a usable remote URI for a Flux instance.
+The input is an "unresolved URI" whose scheme selects the resolver method.
+If no scheme is specified, the default is ``jobid``, thus the following commands
+are equivalent::
+
+ flux uri ÆcbUvuHDCiB
+ flux uri jobid:ÆcbUvuHDCiB
+
+A ``slurm`` scheme enables a Slurm job id to be resolved:
+
+.. code-block:: console
+
+ $ sbatch -N2 --wrap "srun flux start sleep 120"
+ Submitted batch job 1533009
+ $ flux uri slurm:1533009
+ ssh://quartz17/var/tmp/bob/flux-xBj7Cg/local-0
+
+Other schemes are available like ``pid`` and ``lsf``.
+
+flux proxy
+^^^^^^^^^^
+
+It gets a bit tedious setting FLUX_URI for every command, plus each command
+has to initiate a new connection to the remote broker which could be slow.
+:man1:`flux-proxy` establishes a connection once, and spawns a shell with a
+proxy FLUX_URI setting so that commands run within it work seamlessly with the
+remote instance. When the shell exits, the connection is dropped.
+:man1:`flux-proxy` uses the URI resolver so its job ID argument can be an
+unresolved URI.
+
+The :ref:`example above ` can be simplified as follows:
+
+.. code-block:: console
+
+ $ flux batch -N2 --wrap sleep 120
+ ÆcTzRVhnrW3
+ $ flux proxy $(flux job last)
+ Æ(s=2,d=1) $ flux submit --cc 1-5 -N2 sleep 60
+ ÆABfkxas
+ ÆABfkxat
+ ÆABhEwsD
+ ÆABiiw9Z
+ ÆABkCvRu
+ Æ(s=2,d=1) $ flux jobs
+ JOBID USER NAME ST NTASKS NNODES TIME INFO
+ ÆABfkxat bob sleep S 2 2 -
+ ÆABhEwsD bob sleep S 2 2 -
+ ÆABiiw9Z bob sleep S 2 2 -
+ ÆABkCvRu bob sleep S 2 2 -
+ ÆABfkxas bob sleep R 2 2 2.028s test[3-4]
+ Æ(s=2,d=1) $ exit
+ $
+
+.. tip::
+
+ This customized bash shell prompt is neat way to maintain your bearings
+ in a Flux instance hierarchy. Add this to your ``.bashrc``:
+
+ .. code-block:: shell
+
+ if ! echo "$PS1" | grep -q FLUX; then
+ PS1=$'${FLUX_URI+\u0192(s=$(flux getattr size),d=$(flux getattr instance-level)$(which flux|grep -q src/cmd && echo ,builddir))} '${PS1}
+ fi
+
+ ``Æ(s=2,d=1)`` says you're in a Flux instance of size 2 at instance depth 1.
+
+a proxy use case with Hydra
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+:man1:`flux-proxy` can provide interactive access to Flux when the start method
+doesn't support it. A few hints are in order for this use case:
+
+- Make the initial program print the remote URI and then sleep indefinitely.
+
+- Stop the instance with :man1:`flux-shutdown` when it is no longer needed.
+
+- Beware that the interactive proxy shell will get a SIGHUP if the instance
+ terminates while the proxy is in progress. To avoid this, stop the instance
+ *after* exiting the proxy shell.
+
+- Note that unlike :man1:`flux-alloc`, the proxy shell runs locally, not on
+ the first node of the instance.
+
+
+With those points in mind, we can revisit the :ref:`start_hydra` example
+and tweak it to be used interactively:
+
+.. code-block:: console
+
+ $ mpiexec.hydra -f hosts -launcher ssh flux start "flux uri --remote \$FLUX_URI; sleep inf"
+ ssh://test0/tmp/flux-NCPWYE/local-0
+
+Now in another window:
+
+.. code-block:: console
+
+ $ flux proxy ssh://test0/tmp/flux-NCPWYE/local-0
+ Æ(s=8,d=0) $ flux uptime
+ 09:41:03 run 42s, owner bob, depth 0, size 8
+ Æ(s=8,d=0) $ exit
+ exit
+ $ flux shutdown --quiet ssh://test0/tmp/flux-NCPWYE/local-0
+ broker.err[0]: rc2.0: flux uri --remote $FLUX_URI; sleep inf Hangup (rc=129) 52.2s
+ $
+
+The rc2 hangup error indicates that the initial program had to be terminated
+by the shutdown sequence. Normally that would be concerning, but it is expected
+in this situation.
diff --git a/doc/guide/internals.rst b/doc/guide/internals.rst
new file mode 100644
index 000000000000..7ad9ed75e2dc
--- /dev/null
+++ b/doc/guide/internals.rst
@@ -0,0 +1,10 @@
+Resources for Flux Developers
+=============================
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contents:
+
+ debug
+ kvs
+ broker
diff --git a/doc/guide/kvs.rst b/doc/guide/kvs.rst
new file mode 100644
index 000000000000..3474e7af0ae3
--- /dev/null
+++ b/doc/guide/kvs.rst
@@ -0,0 +1,320 @@
+.. _kvs:
+
+###############
+Key Value Store
+###############
+
+The Flux key value store is an essential building block for Flux services.
+This page describes the current KVS design.
+
+As described in
+`SRMPDS 2014 `_,
+the Flux KVS is a general purpose data store used by other Flux components.
+It stores values under a hierarchical key space with a single leader
+node and multiple caching followers. The weak consistency of its follower
+caches has the following properties, using the taxonomy from
+`Vogel 2007 `_:
+
+Causal consistency
+ If process A communicates with process B that it has updated a data item
+ (passing a store version in that message), a subsequent access by process
+ B will return the updated value.
+
+Read-your-writes consistency
+ A process having updated a data item, never accesses an older value.
+
+Monotonic read consistency
+ If a process has seen a particular value for an object, any subsequent
+ accesses will never return previous values.
+
+These properties are achieved with hash trees and content-addressable storage,
+borrowing ideas from
+`ZFS `_,
+`camlistore `_, and
+`git `_.
+KVS values and metadata are placed in a content-addressable store,
+indexed by their hash digests, or *blobrefs*. The content store is described
+in :doc:`RFC 10 ` and briefly below.
+
+KVS metadata consist of directories, symbolic links, and value references,
+formatted as JSON objects. These objects are described in
+:doc:`RFC 11 ` and briefly below.
+
+**********
+key lookup
+**********
+
+Path components of a key each reference a directory entry in a different
+directory. The first path component is looked up by following a root
+blobref to the root directory, finding a matching entry, and following
+that blobref to a new entry, and so on until the terminal name is reached
+and the resulting object is returned to the user.
+
+For example, if the root blobref is ``sha1-1c002dde`` and we have stored
+*a.b.c = 42*, we would look it up as follows:
+
+1. load root directory from ``sha1-1c002dde``, find *a* is at
+ ``sha1-3f2243ef``
+2. load *a* from ``sha1-3f2243ef``, find *b* is at ``sha1-023e9b2d``
+3. load *b* from ``sha1-023e9b2d``, find *c* is at ``sha1-7ff234a8``
+4. load *c* from ``sha1-7ff234a8``, and return the value: *42*.
+
+It's actually slightly more complicated than that since large directories
+and values can span multiple blobs. Instead of always a single blobref,
+directory entries contain a *dirref* or *valref* object that contain
+arrays of blobrefs. Following a *dirref* to the next *dir* object
+may require fetching multiple blobs to reconstruct the next object.
+Retrieving a value from a *valref* may similarly require fetching multiple
+blobs to reconstruct the final value. Finally, as an optimization,
+small values may be included directly in a directory entry in a *val* object.
+
+The basic KVS API for looking up a value by key is described in
+:man3:`flux_kvs_lookup`.
+
+
+**********
+key update
+**********
+
+An important property of the hash tree structure is that any update
+results in a new root blobref . Continuing the example,
+to update *a.b.c = 43*, we:
+
+1. store the value *43* to ``sha1-62302aff``
+2. update *b* to associate *c* with ``sha1-62302aff``, and
+ store *b* to ``sha1-8fe9b2c3``
+3. update *a* to associate *b* with ``sha1-8fe9b2c3``, and
+ store *a* to ``sha1-aacc76b4``
+4. update root to associate *a* with ``sha1-aacc76b4``, and
+ store root to ``sha1-033fbe92``
+5. the new root blobref is ``sha1-033fbe92``.
+
+All updates are applied first on the leader node at the root of the TBON,
+which then publishes a new root reference as a *setroot* event. Followers keep
+consistent with the leader by switching their root reference in response to
+this event, so that all new lookups begin at the new root directory.
+
+Updates are transactional in that multiple changes can be batched up into
+a single *commit*, which either succeeds or fails entirely, without making
+intermediate states visible to users.
+
+The basic KVS API for updating keys is described in :man3:`flux_kvs_txn_create`
+and :man3:`flux_kvs_commit`.
+
+*************
+content cache
+*************
+
+As mentioned above, a distinct distributed service, used by the KVS,
+maps blobrefs to blobs, and implements a temporal cache on
+each broker rank, backed ultimately by a sqlite database on rank 0.
+
+When the KVS is performing a key lookup, tree objects are retrieved from
+the content cache by blobref. Blobs not present in the local
+broker's content cache are faulted in from the TBON parent, recursing
+up the tree until the request can be fulfilled. Unused content cache
+entries are expired from memory after a period of disuse. They persist
+in the sqlite database, which does not allow blobs to be deleted.
+
+A store to the content cache is allowed to return once the entry is
+present in the rank 0 memory cache, since this ensures it can be read
+by any rank. It must be written to sqlite before it can be expired
+from the rank 0 memory cache.
+
+The content store can be used independently, e.g. through the command line
+as described in :man1:`flux-content` or or by sending the RPCs described
+in :doc:`RFC 10 `.
+
+**********
+namespaces
+**********
+
+The KVS supports multiple namespaces. The *primary namespace* is
+always available and can only be accessed by the :term:`instance owner`.
+
+The instance owner can create and destroy additional namespaces,
+and assign each an *owner* who can access the namespace, in addition
+to the instance owner which can access all namespaces. In Flux, each job
+is set up with its own namespace, owned by the job owner, who may be a
+:term:`guest` user.
+
+Although commits are serialized on a given namespace, commits on
+distinct namespaces can progress in parallel.
+
+***********
+consistency
+***********
+
+Flux event messages are sequenced and guaranteed to be delivered in order.
+This property, and the serialization of commits on the leader node, ensure
+that monotonic read consistency is achieved.
+
+Read-your-writes consistency is obtained by piggy-backing on the commit
+response the new root blobref and its version number, a monotonic sequence.
+As the response propagates from the leader node to the sender of the commit
+through a sequence of followers, the followers update their root reference to
+at least the version in the response. Thus, once a commit response is
+received, a lookup initiated by the caller will always return that version
+of the store or newer. Races with the setroot event are avoided by minding
+the sequence number so root updates are never applied out of sequence.
+
+Causal consistency is available programmatically. After a commit, the root
+blobref version can be read via :man3:`flux_kvs_commit_get_sequence`
+or :func:`flux_kvs_get_version` and passed to another rank, which can use
+:func:`flux_kvs_wait_version` to block until the follower root blobref
+reaches that version, after which the data from the commit (or newer) can
+be retrieved. In summary:
+
+1. Process A commits data, then gets the store version :math:`V` and sends
+ it to B.
+2. Process B waits for the store version to be :math:`>= V`, then reads data.
+
+**********************
+the secret other cache
+**********************
+
+In the current KVS implementation, there is a cache of content blobs
+in the KVS module that sits in front of the content cache service.
+Cached blobs are accessible directly rather than through RPC to the
+local content cache service, except when there is a "fault",
+and then access must be suspended while the RPC completes. This local
+cache is temporally expired like the content cache service.
+
+When a request to look up a name is handled and a needed tree object
+(for example a directory in the middle of a path) is not in cache, the
+request message is queued on a cache entry that is waiting to be filled.
+Once the cache entry has been filled, the request message queued on it is
+"restarted" meaning handled like a new request. Since all the tree objects
+for the lookup up to that point should be in cache, it won't block until it
+reaches the next missing tree object. Multiple requests can be queued on
+each cache entry, but only one content request is triggered regardless of
+how many consumers there are for it. This design was an optimization for
+many requests looking up the same thing such as during a PMI exchange.
+
+***********************
+treeobj metadata format
+***********************
+
+:doc:`RFC 11 ` defines the treeobj format, but here is a brief
+summary:
+
+A *valref* refers to opaque data in the content store (the actual data,
+not a *val* object).
+
+.. code-block:: json
+
+ { "ver":1,
+ "type":"valref",
+ "data":["sha1-aaa...","sha1-bbb..."],
+ }
+
+A *val* represents opaque data directly, base64-encoded.
+
+.. code-block:: json
+
+ { "ver":1,
+ "type":"val",
+ "data":"NDIyCg==",
+ }
+
+A *dirref* refers to a *dir* or *hdir* object that was serialized and
+stored in the content store.
+
+.. code-block:: json
+
+ { "ver":1,
+ "type":"dirref",
+ "data":["sha1-aaa...","sha1-bbb..."],
+ }
+
+A *dir* is a dictionary mapping keys to any of the tree object types.
+
+.. code-block:: json
+
+ { "ver":1,
+ "type":"dir",
+ "data":{
+ "a":{"ver":1,"type":"dirref","data":["sha1-aaa"]},
+ "b":{"ver":1,"type":"val","data":"NDIyCg=="},
+ "c":{"ver":1,"type":"valref","data":["sha1-aaa","sha1-bbb"]},
+ "d":{"ver":1,"type":"dir","data":{},
+ }
+ }
+
+A *symlink* is a symbolic pointer to a another KVS key, which may
+or may not be fully qualified.
+
+.. code-block:: json
+
+ { "ver":1,
+ "type":"symlink",
+ "data":"a.aa",
+ }
+
+*****
+watch
+*****
+
+Any key (including the root directory) can be "watched", such that a user
+receives responses for each key change.
+
+Watch is implemented in a separate ``kvs-watch`` module.
+
+Each time a setroot event indicates that something has changed, the
+``kvs-watch`` module looks up the watched keys to see if they have changed.
+
+Because watched keys have to be looked up from the root on *every* KVS
+commit, watching a key has a high overhead, but some relief is given by
+the optimization of including a list of changed keys in the setroot event,
+described below.
+
+The API for watching KVS keys is described in :man3:`flux_kvs_lookup`.
+Basically a special flag is added and responses are received each time
+the value changes or the request is canceled or the caller disconnects.
+
+*************
+optimizations
+*************
+
+piggyback root directory on setroot event
+=========================================
+
+The KVS design calls for publication of a setroot event each time
+the root blobref changes.
+
+Since most lookups will need to start with the root directory
+(the object pointed to by the root blobref), the new root directory will
+most likely not be in cache, and any watched keys will be looked up on
+every commit, the root directory object is made part of the setroot event
+so this lookup is avoided.
+
+commit merging
+==============
+
+Since all updates are serialized through the rank 0 commit process,
+this area of the code is an obvious target for optimization.
+One such optimization is commit merging.
+
+*commit merging* is implemented by queuing parsed commit requests
+during the main part of the reactor loop, and processing them only
+when the reactor has no events (request messages) pending, using
+the prepare/check/idle watcher pattern.
+
+This minimizes the work that is duplicated for each commit: creating
+a temporary in-memory json object to work on, and updating the root
+reference and top level directories when the commit is finalized.
+This saves time, but also reduces the number of intermediate objects
+written to the content cache.
+
+A problem arises when intermediate values for a key are overwritten
+in merged commits, and a "watcher" needs to see each value to function
+properly, such as to synchronize a state machine. To solve this,
+a ``KVS_NO_MERGE`` flag may be added to :func:`flux_kvs_commit`, which
+indicates that the merge should not be subject to this optimization.
+
+piggyback list of changed keys on setroot event
+===============================================
+
+To streamline the KVS watch implementation, a list of changed keys is
+included in the kvs setroot event. That way the entire list of watched keys
+does not need to be looked up every time there is a new root.
diff --git a/doc/guide/start.rst b/doc/guide/start.rst
new file mode 100644
index 000000000000..2a2c04ffd41d
--- /dev/null
+++ b/doc/guide/start.rst
@@ -0,0 +1,496 @@
+Starting a Flux Instance
+========================
+
+A *Flux instance* is a self-contained workload manager. It is so easy to
+start a new Flux instance that we often ask ourselves "can we just start a
+new instance?" before we consider extending Flux to solve a new problem.
+
+In a broad sense, Flux is a workload manager on a par with Slurm, Torque,
+LSF, or similar systems. It distinguishes itself by being able to be started
+standalone, as a job in another system, or a job in *itself* (recursively).
+It doesn't require elevated privileges to do so for one user at a time, so
+anyone can download Flux and immediately use it productively. This opens up
+possibilities for using Flux as a portability layer or "step scheduler" in
+workflow systems, and for cooking up divide and conquer solutions to
+resource and workload problems.
+
+A Flux instance consists of a set of services running on top of a distributed
+message broker. To start Flux, we are just starting one or more brokers in
+parallel, as a *parallel program* if you will.
+
+:man1:`flux-start` starts a Flux instance, whose life cycle consists of three
+phases:
+
+#. Initialize
+#. The rank 0 broker runs the :term:`initial program` to completion
+#. Finalize
+
+By default, the initial program is an interactive shell. If :man1:`flux-start`
+is passed free arguments, they are interpreted as commands to run
+non-interactively instead. Either way, when the initial program terminates,
+the instance terminates.
+
+.. _test_instance:
+
+Starting a Test Instance
+------------------------
+
+A standalone Flux instance can be started right away, say on your laptop, or
+on a login node of your institution's big cluster. This is a convenient way to
+begin experimenting.
+
+.. code-block:: console
+
+ $ flux start --test-size=3
+ $ flux uptime
+ 23:50:28 run 1.3m, owner alice, depth 0, size 3
+ $ flux resource info
+ 3 Nodes, 12 Cores, 0 GPUs
+ $ flux run --label-io -N3 hostname
+ 2: test0
+ 1: test0
+ 0: test0
+ $ exit
+ $
+
+What just happened? Hint: the process tree looks like this:
+
+.. code-block:: console
+
+ flux-startââŦâflux-broker-0âââbash
+ ââflux-broker-1
+ ââflux-broker-2
+
+Let's break it down:
+
+#. :man1:`flux-start` launches three Flux brokers on the local system,
+ ranked 0, 1, and 2.
+
+#. The brokers find their rank and exchange peer network addresses and public
+ keys using a `PMI server `_
+ offered by the start command, which is the process parent of the brokers.
+ The PMI server is only offered by :man1:`flux-start` when the
+ ``--test-size=N`` option is used.
+
+#. After the brokers are connected and have completed initialization, the
+ rank 0 broker spawns the initial program, an interactive shell that has its
+ environment set up so that Flux commands run from it will connect to the
+ new Flux instance. The prompt right after the start command is from this
+ new shell.
+
+#. We run :man1:`flux-uptime` to get some basic info about the system and note
+ that it consists of three brokers, and that it has no parent instance, hence
+ a "depth" of zero.
+
+#. We run :man1:`flux-resource` *list* to show the instance's resource
+ inventory. In this contrived test instance, we have three brokers running
+ on one node, but each broker assumes that it is discovering the resources
+ of a separate node, so while there is really 1 node, 4 cores, the
+ resource inventory contains 3 nodes, 12 cores. See below for more on that.
+
+#. :man1:`flux-run` launches the :linux:man1:`hostname` command in
+ parallel across the three "nodes" and waits for it to complete.
+ We observe that each reports the same hostname.
+
+#. Finally, we exit the interactive shell. Since that was the initial program,
+ the instance exits. The next prompt is the original shell, before we ran
+ the start command.
+
+It is convenient to be able to start a Flux instance like this in pretty much
+any environment, but to reinforce what was alluded to above, the main
+caveat of a test instance is that it doesn't actually have exclusive access
+to resources. `HWLOC `_ is used to
+discover what hardware is out there on each broker, but the broker has no way
+to claim it exclusively. A test instance on a shared login node provides the
+illusion of exclusive access to jobs run within it, but someone else running
+a test instance on the same node may be doing the same thing. Furthermore,
+when the test size is greater than one, the actual hardware resources may be
+oversubscribed within the single instance.
+
+Let's create a script to run as the initial program in place of the interactive
+shell. Call this script ``workload.sh``. It runs the same commands as were
+run above, in a way that works on any size instance.
+
+.. code-block:: shell
+
+ #!/bin/sh
+ flux resource info
+ flux uptime
+ NNODES=$(flux resource list -no {nnodes})
+ flux run --label-io -N $NNODES hostname
+
+When we run this way, we get the same result as above, but the user doesn't
+have to provide any input while the instance is running:
+
+.. code-block:: console
+
+ $ flux start --test-size=3 ./workload.sh
+ 3 Nodes, 12 Cores, 0 GPUs
+ 10:00:30 run 2.9s, owner alice, depth 0, size 3
+ 0: test0
+ 2: test0
+ 1: test0
+ $
+
+This is how many of Flux-core's tests work. The initial program is a test
+script run under a test instance started by the test suite.
+
+Starting with Slurm
+-------------------
+
+When :man1:`flux-start` is run without the ``--test-size=N`` option, it
+simply execs the broker rather than sticking around to provide PMI service.
+The broker uses its PMI client to determine its place in a parallel program,
+or if PMI is not found, it runs as a singleton.
+
+So to start a Flux instance in a foreign resource manager, we just run
+:man1:`flux-start` in parallel as though it were an MPI job, usually with
+one broker per node in the foreign allocation.
+
+.. note::
+ Slurm has a few different options that control the parallel environment
+ for jobs. If your site has not configured ``MpiDefault=pmi2``, then it may
+ be necessary to run flux with the srun ``--mpi=pmi2`` option. If a parallel
+ launch of Flux results in multiple singletons, e.g. reporting 1 node when
+ more were expected, this may help.
+
+In Slurm, we can obtain an allocation with `salloc(1)
+`_. From the interactive shell
+it spawns, we use `srun(1) `_
+to start a Flux instance. The ``--pty`` option gives Flux's interactive
+initial program a proper terminal.
+
+.. code-block:: console
+
+ $ salloc -N2
+ salloc: Pending job allocation 1505790
+ salloc: job 1505790 queued and waiting for resources
+ salloc: job 1505790 has been allocated resources
+ salloc: Granted job allocation 1505790
+ salloc: Waiting for resource configuration
+ salloc: Nodes quartz[2257-2258] are ready for job
+ $ srun -N2 --pty flux start
+ $ flux uptime
+ 10:04:05 run 6.6s, owner alice, depth 0, size 2
+ $ flux resource info
+ 2 Nodes, 72 Cores, 0 GPUs
+ $ flux run -N2 hostname
+ quartz2257
+ quartz2258
+ $ exit
+ $ exit
+ salloc: Relinquishing job allocation 1505790
+ salloc: Job allocation 1505790 has been revoked.
+ $
+
+After typing the same two Flux commands that were demonstrated in
+:ref:`test_instance`, we exit the Flux interactive shell, then the
+Slurm one, which gives up the Slurm allocation.
+
+Conceptually, what's going on here is Slurm has granted a resource
+allocation to Flux, which then parcels it out to the jobs submitted to it.
+
+The above can be accomplished a little more succinctly by just running
+srun directly. Then the session looks like this:
+
+.. code-block:: console
+
+ $ srun -N2 --pty flux start
+ srun: job 1505791 queued and waiting for resources
+ srun: job 1505791 has been allocated resources
+ $ flux uptime
+ 10:05:51 run 4.7s, owner alice, depth 0, size 2
+ $ flux resource info
+ 2 Nodes, 72 Cores, 0 GPUs
+ $ flux run --label-io -N2 hostname
+ 0: quartz2257
+ 1: quartz2258
+ $ exit
+ $
+
+To run non-interactively, we can drop the ``--pty`` option and use our
+workload script for the initial program:
+
+.. code-block:: console
+
+ $ srun -N2 flux start ./workload.sh
+ srun: job 1505795 queued and waiting for resources
+ srun: job 1505795 has been allocated resources
+ 10:07:12 run 4.6s, owner alice, depth 0, size 2
+ 2 Nodes, 72 Cores, 0 GPUs
+ 0: quartz25
+ 1: quartz26
+
+Finally, Slurm batch execution of a Flux workload can be accomplished
+by wrapping the srun command in a batch script we will name ``batch.sh``:
+
+.. code-block:: shell
+
+ #!/bin/sh
+ #SBATCH -N2
+ srun flux start ./workload.sh
+
+Whee!
+
+.. code-block:: console
+
+ $ sbatch ./batch.sh
+ Submitted batch job 1505846
+ $ cat slurm-1505846.out
+ 10:09:57 run 4.8s, owner alice, depth 0, size 2
+ 2 Nodes, 72 Cores, 0 GPUs
+ 0: quartz47
+ 1: quartz48
+ $
+
+Inserting Flux between Slurm and a real workload script or workflow executor
+could have some advantages, such as:
+
+- Workload scripts that use Flux commands or the Flux python API can be made
+ portable to other systems that don't use Slurm as their primary resource
+ manager, as long as they can launch a Flux instance.
+
+- High throughput workloads are less of a burden on the Slurm controller
+ and may run faster compared to the same workload run with job steps, since
+ `Step Allocation `_
+ involves an RPC to the Slurm controller.
+
+- When combined with the `flux-sched project
+ `_, Flux offers more
+ sophisticated step scheduling.
+
+- A Flux instance may be tailored by the instance owner to meet the specific
+ demands of the workload. For example, the scheduler algorithm may be
+ changed.
+
+To be clear, Flux does not have "steps" per se, only jobs. We don't need them
+since Flux batch jobs are just regular Flux jobs that happen to be independent
+Flux instances, and Flux instances have the capability to run more Flux jobs.
+
+Since Slurm runs on many of the largest HPC systems, the capability to launch
+Flux instances under Slurm provided early opportunities to work on Flux
+portability and scalability on those systems without requiring much buy-in from
+the system owners, other than permission to run there.
+
+Starting with Flux
+------------------
+
+Flux can run parallel programs, and a Flux instance can be run as one, so Flux
+can run Flux. No surprise there. What does that look like and how is it
+leveraged to provide expected workload manager abstractions?
+
+First let's try our workload commands in the "outer" Flux instance, in this
+case a standalone :term:`system instance`, although this section applies to all
+Flux instances.
+
+.. code-block:: console
+
+ $ flux uptime
+ 10:13:27 run 23d, owner flux, depth 0, size 101, 7 drained, 8 offline
+ $ flux resource info
+ 98 Nodes, 392 Cores, 0 GPUs
+ $ flux run -N2 hostname
+ $ flux run --label-io -N2 hostname
+ 0: fluke6
+ 1: fluke7
+
+The instance depth is zero since this is the system instance. We also get a
+heads up about some unavailable nodes, and note that the instance owner is
+the ``flux`` user, but otherwise this looks like before. Now, an interactive
+Flux allocation:
+
+.. code-block:: console
+
+ $ flux alloc -N2
+ $ flux uptime
+ 10:16:58 run 7.3s, owner alice, depth 1, size 2
+ $ flux resource info
+ 2 Nodes, 8 Cores, 0 GPUs
+ $ flux run -N2 hostname
+ fluke6
+ fluke7
+ $ exit
+ $
+
+The :man1:`flux-alloc` command spawns a new Flux instance in the allocation
+automatically. The instance depth is now 1. This is an example of how Flux's
+recursive launch property simplifies its design: instead of requiring
+specialized code to support interactive allocations, Flux just transfers the
+requested resources to a new instance that runs for the life of its initial
+program, the interactive shell.
+
+As a side note, while :man1:`flux-alloc` provides an interface that is
+convenient as well as familiar to Slurm users, we could have accomplished
+the same thing with :man1:`flux-run` and :man1:`flux-start`:
+
+.. code-block:: console
+
+ $ flux run -N2 -o pty.interactive flux start
+ $ flux uptime
+ 10:19:27 run 8.3s, owner alice, depth 1, size 2
+ $ flux resource info
+ 2 Nodes, 8 Cores, 0 GPUs
+ $ flux run --label-io -N2 hostname
+ 0: fluke6
+ 1: fluke7
+ $ exit
+ [detached: session exiting]
+ $
+
+Now let's try batch:
+
+.. code-block:: console
+
+ $ flux batch -N2 ./workload.sh
+ f2SoPsfdA7Ub
+ $ cat flux-f2SoPsfdA7Ub.out
+ 10:25:05 run 4.8s, owner alice, depth 1, size 2
+ 2 Nodes, 8 Cores, 0 GPUs
+ 0: fluke6
+ 1: fluke7
+
+Like the allocation example, the :man1:`flux-batch` command spawns a new Flux
+instance that runs for the duration of its initial program, the batch script
+``workload.sh``. The Flux design does not require job steps or a specialized
+step scheduler because of the recursive launch property.
+
+Although :man1:`flux-batch` has other nice features like support for batch
+directives and copying of the batch script at submission, a similar result
+can be obtained for this simple example with :man1:`flux-submit` and
+:man1:`flux-start`:
+
+.. code-block:: console
+
+ $ flux submit --output=flux-{{id}}.out -N2 flux start ./workload.sh
+ f2SoiFq3N5Jo
+ $ cat flux-f2SoiFq3N5Jo.out
+ 11:05:24 run 4.7s, owner alice, depth 1, size 2
+ 2 Nodes, 8 Cores, 0 GPUs
+ 0: fluke6
+ 1: fluke7
+
+.. _start_hydra:
+
+Starting with Hydra
+-------------------
+
+MPICH `hydra `_
+is an MPI launcher with PMI support that can start a Flux instance across
+multiple nodes using ssh. It is sometimes just the right tool needed to get
+a Flux instance going when nothing else will work.
+
+Given a ``hosts`` file containing:
+
+::
+
+ test0
+ test1
+ test2
+ test3
+ test4
+ test5
+ test6
+ test7
+
+And assuming passwordless ssh works for those nodes, one can run:
+
+.. code-block:: console
+
+ $ mpiexec.hydra -launcher ssh -f hosts flux start ./workload.sh
+ 23:23:14 run 3.9s, owner alice, depth 0, size 8
+ 8 Nodes, 32 Cores, 0 GPUs
+ 0: test0
+ 2: test2
+ 1: test1
+ 5: test5
+ 6: test6
+ 7: test7
+ 4: test4
+ 3: test3
+
+Starting with Static Configuration
+----------------------------------
+
+In the methods described above, Flux brokers determine their ranks and
+exchange peer network addresses and public keys using PMI. In situations
+where PMI is unavailable or inappropriate, the same information can be loaded
+from static configuration files. As an example, we'll start Flux on the same
+eight nodes from :ref:`start_hydra`.
+
+Generate a shared CURVE certificate that will be used to secure the overlay
+network:
+
+.. code-block:: console
+
+ $ mkdir test
+ $ cd test
+ $ flux keygen test.cert
+ $
+
+Create a TOML config file as described in :man5:`flux-config-bootstrap`.
+We'll call it ``test.toml``. For this experiment, we can place it in the
+same directory as ``test.cert``:
+
+.. code-block:: toml
+
+ [bootstrap]
+ curve_cert = "/home/bob/test/test.cert"
+
+ hosts = [
+ { host="test0", bind="tcp://eth0:8060", connect="tcp://test0:8060" },
+ { host="test1", bind="tcp://eth0:8060", connect="tcp://test1:8060" },
+ { host="test2", bind="tcp://eth0:8060", connect="tcp://test2:8060" },
+ { host="test3", bind="tcp://eth0:8060", connect="tcp://test3:8060" },
+ { host="test4", bind="tcp://eth0:8060", connect="tcp://test4:8060" },
+ { host="test5", bind="tcp://eth0:8060", connect="tcp://test5:8060" },
+ { host="test6", bind="tcp://eth0:8060", connect="tcp://test6:8060" },
+ { host="test7", bind="tcp://eth0:8060", connect="tcp://test7:8060" },
+ ]
+
+If necessary, replicate the ``test`` directory across the eight nodes.
+
+Finally, start a broker on each node. You can use any technique you like,
+but keep in mind the brokers will not exit until the initial program completes,
+and the initial program will not start until all the brokers are online.
+We use :linux:man1:`pdsh` to start the brokers in parallel and capture any
+errors they print to the standard error stream:
+
+.. code-block:: console
+
+ $ pdsh -N -w test[0-7] flux start -o,--config-path=/home/bob/test/test.toml ./workload.sh
+ 8 Nodes, 32 Cores, 0 GPUs
+ 00:03:31 run 2.5s, owner bob, depth 0, size 8
+ 0: test0
+ 6: test6
+ 7: test7
+ 4: test4
+ 5: test5
+ 1: test1
+ 3: test3
+ 2: test2
+
+This method of starting Flux is used when `systemd `_
+starts brokers belonging to a Flux system instance. This is described in the
+`Flux Administration Guide
+`_.
+Another example is the `Flux Operator
+`_, which uses dynamically generated
+configuration to bootstrap Flux in a Kubernetes cluster.
+
+When compared with PMI bootstrap, this method of starting Flux has the
+following drawbacks:
+
+- Managing and sharing the instance-specific files is an extra step.
+
+- The CURVE certificate must be protected from disclosure to parties other
+ than the Flux instance owner, or an attacker may attach and impersonate
+ the owner.
+
+- The use of a fixed port number in the configuration raises the possibility
+ that the port may already be in use on one of the nodes, especially if the
+ same configuration file is reused. If a broker cannot bind to its port,
+ it will fail to start.
+
+- If a broker fails to start, the ``pdsh`` command line above may hang.
+ Options are available to deal with this like the ``broker.quorum`` setting
+ described in :man7:`flux-broker-attributes`.
diff --git a/doc/guide/support.rst b/doc/guide/support.rst
new file mode 100644
index 000000000000..8b99605d1097
--- /dev/null
+++ b/doc/guide/support.rst
@@ -0,0 +1,57 @@
+License and Support
+===================
+
+License
+-------
+
+.. figure:: images/lgplv3-147x51.png
+ :alt: LGPL-3.0 logo
+ :align: right
+
+Flux-core is licensed under `LGPL-3.0
+`_ which means project forks
+must retain the same license and follow the license's requirements for making
+source code available to end users.
+
+Software that merely uses flux-core's APIs may be independently licensed.
+
+Support
+-------
+
+All flux-core issues and changes are proposed and discussed on `Github
+`_. The team values
+openness and inclusivity and encourages collaboration. Engage with us!
+
+If you have a problem that might be a flux-core bug, please first search
+existing issues, then open a new `Github issue
+`_ if necessary.
+Be sure to include relevant context and especially the flux version that
+is exhibiting the problem:
+
+.. code-block:: console
+
+ $ flux version
+ commands: 0.54.0
+ libflux-core: 0.54.0
+ libflux-security: 0.10.0
+ build-options: +systemd+hwloc==2.4.0+zmq==4.3.4
+
+`Github discussions `_
+are sometimes useful too.
+
+Development Commitment
+----------------------
+
+At this time, Lawrence Livermore National Laboratory (LLNL) has a team of
+four full time employees working on flux-core, and several additional employees
+and collaborators working on the broader Flux Framework and related research
+areas. LLNL is committed to making Flux a production quality tool for HPC
+workload management, and has sustained its investment for over a decade thus
+far.
+
+Flux is part of the `TOSS `_
+operating system and thus is supported across multiple U.S. national laboratory
+facilities.
+
+The Flux team welcomes all users and contributors to the Flux community and
+will do its best enable the community to grow and thrive.
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 000000000000..b323c14ed859
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,108 @@
+Flux Core
+=========
+
+The flux-core project provides the distributed messaging capability and core
+services and APIs of the Flux resource manager framework. Flux-core has been
+under active development since 2012, primarily at Lawrence Livermore National
+Laboratory. The flux-core project implements several of Flux's innovations:
+
+Recursive launch
+ A Flux instance can be launched standalone for testing, by systemd as a
+ system service, or as a parallel job under most HPC resource managers and
+ launchers, including Flux itself. A Flux batch job or interactive allocation
+ is an independent Flux instance running on a subset of the parent's
+ resources. Resources can be recursively subdivided ad infinitum for
+ performance or isolation.
+
+Small Security Footprint
+ Flux-core does not contain any code that runs as root. A Flux instance
+ only requires a setuid helper (provided by the flux-security project) in
+ multi-user configurations. Flux can be deployed for single user use without
+ administrator access.
+
+Reactive Messaging
+ Flux components are primarily single threads that communicate only by
+ exchanging messages through message brokers. C and Python APIs enable
+ the creation of robust, distributed services that use this paradigm.
+
+Related Information
+===================
+
+Although able to function on its own, flux-core's capability is enhanced when
+combined with other framework projects. Those wishing to deploy Flux as a
+full-featured resource management solution or understand Flux in a broader
+context may benefit from the following material:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Description
+ - Links
+
+ * - Main Flux Documentation Pages
+ - `Docs `_
+
+ * - Flux as the primary resource manager on an HPC cluster
+ - `Flux Administrator's Guide `_
+
+ * - Flux Request for Comments Specifications
+ - `RFC `_
+
+For high performance computing users, the key framework projects are
+currently:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Framework Project
+ - Links
+
+ * - flux-core - Base Flux framework
+ - `Github `_
+
+ `Docs `_ - You are already here!
+
+ * - flux-sched - Fluxion graph-based scheduler
+
+ Required for complex resource types and scheduling beyond FIFO
+
+ - `Github `_
+
+ `Docs `_
+
+ * - flux-security - Job request signatures and setuid helper
+
+ Required for multi-user Flux instances
+
+ - `Github `_
+
+ `Docs `_
+
+ * - flux-accounting - Bank accounting and fair share priority
+ - `Github `_
+
+ `Flux Accounting Guide `_
+
+ * - flux-pmix - OpenMPI support
+ - `Github `_
+
+ * - flux-coral2 - Cray MPI and rabbit storage support
+ - `Github `_
+
+ `CORAL2: Flux on Cray Shasta `_
+
+Table of Contents
+=================
+
+.. toctree::
+ :maxdepth: 2
+
+ guide/build
+ guide/support
+ guide/start
+ guide/interact
+ guide/admin
+ guide/glossary
+ index_man
+ python/index
+ guide/internals
diff --git a/doc/index_man.rst b/doc/index_man.rst
new file mode 100644
index 000000000000..3e5eb89162c4
--- /dev/null
+++ b/doc/index_man.rst
@@ -0,0 +1,12 @@
+.. _man-pages:
+
+Manual Pages
+============
+
+.. toctree::
+ :maxdepth: 1
+
+ man1/index
+ man3/index
+ man5/index
+ man7/index
diff --git a/doc/man1/COPYRIGHT.adoc b/doc/man1/COPYRIGHT.adoc
deleted file mode 100644
index 6b2304f95801..000000000000
--- a/doc/man1/COPYRIGHT.adoc
+++ /dev/null
@@ -1,4 +0,0 @@
-Copyright 2014 Lawrence Livermore National Security, LLC
-and Flux developers.
-
-SPDX-License-Identifier: LGPL-3.0
diff --git a/doc/man1/Makefile.am b/doc/man1/Makefile.am
deleted file mode 100644
index c4a1d66ba462..000000000000
--- a/doc/man1/Makefile.am
+++ /dev/null
@@ -1,63 +0,0 @@
-MAN1_FILES = $(MAN1_FILES_PRIMARY) $(MAN1_FILES_SECONDARY)
-
-
-MAN1_FILES_PRIMARY = \
- flux.1 \
- flux-broker.1 \
- flux-kvs.1 \
- flux-keygen.1 \
- flux-logger.1 \
- flux-ping.1 \
- flux-start.1 \
- flux-module.1 \
- flux-exec.1 \
- flux-env.1 \
- flux-getattr.1 \
- flux-dmesg.1 \
- flux-content.1 \
- flux-hwloc.1 \
- flux-proxy.1 \
- flux-cron.1 \
- flux-user.1 \
- flux-event.1 \
- flux-mini.1 \
- flux-version.1 \
- flux-jobs.1
-
-# These files are generated as roff .so includes of a primary page.
-# A2X handles this automatically if mentioned in NAME section
-MAN1_FILES_SECONDARY = \
- flux-setattr.1 \
- flux-lsattr.1
-
-
-ADOC_FILES = $(MAN1_FILES_PRIMARY:%.1=%.adoc)
-XML_FILES = $(MAN1_FILES_PRIMARY:%.1=%.xml)
-
-if ENABLE_DOCS
-dist_man_MANS = $(MAN1_FILES)
-$(MAN1_FILES): COPYRIGHT.adoc NODESET.adoc
-endif
-
-SUFFIXES = .adoc .1
-
-flux-setattr.1: flux-getattr.1
-flux-lsattr.1: flux-getattr.1
-
-STDERR_DEVNULL = $(stderr_devnull_$(V))
-stderr_devnull_ = $(stderr_devnull_$(AM_DEFAULT_VERBOSITY))
-stderr_devnull_0 = 2>/dev/null
-
-.adoc.1:
- $(AM_V_GEN)$(ADOC) --attribute mansource=$(PACKAGE_NAME) \
- --attribute manversion=$(PACKAGE_VERSION) \
- --attribute manmanual="Flux Command Reference" \
- --destination-dir $(builddir) \
- --doctype manpage $(ADOC_FORMAT_OPT) manpage $< $(STDERR_DEVNULL)
-
-EXTRA_DIST = \
- $(ADOC_FILES) \
- COPYRIGHT.adoc \
- NODESET.adoc
-
-CLEANFILES = $(MAN1_FILES) $(XML_FILES)
diff --git a/doc/man1/NODESET.adoc b/doc/man1/NODESET.adoc
deleted file mode 100644
index a86142172e2c..000000000000
--- a/doc/man1/NODESET.adoc
+++ /dev/null
@@ -1,14 +0,0 @@
-A NODESET is a comma separated list of integer ranks. Ranks may be
-listed individually or as a range in the form _l-k_ where l < k.
-
-Some examples of nodesets.
-
-[horizontal]
-``1'':: rank 1
-``0-3'':: ranks 0, 1, 2, and 3 listed in a range
-``0,1,2,3'':: ranks 0, 1, 2, and 3 listed individually
-``2,5'':: ranks 2 and 5
-``2,4-5'':: ranks 2, 4, and 5
-
-As a special case, the string ``_all_'' can be specified to indicate every
-rank available in the flux instance.
diff --git a/doc/man1/common/experimental.rst b/doc/man1/common/experimental.rst
new file mode 100644
index 000000000000..00be899898a2
--- /dev/null
+++ b/doc/man1/common/experimental.rst
@@ -0,0 +1,4 @@
+Experimental Flux features and interfaces are made available for evaluation
+only and may change or be removed without notice.
+
+Feedback is welcome. Please use the flux-core project Github issue tracker.
diff --git a/doc/man1/common/job-constraints.rst b/doc/man1/common/job-constraints.rst
new file mode 100644
index 000000000000..0f8c280feb0b
--- /dev/null
+++ b/doc/man1/common/job-constraints.rst
@@ -0,0 +1,71 @@
+.. option:: --requires=CONSTRAINT
+
+ Specify a set of allowable properties and other attributes to consider
+ when matching resources for a job. The **CONSTRAINT** is expressed in
+ a simple syntax described in RFC 35 (Constraint Query Syntax) which is
+ then converted into a JSON object compliant with RFC 31 (Job Constraints
+ Specification).
+
+ A constraint query string is formed by a series of terms.
+
+ A term has the form ``operator:operand``, e.g. ``hosts:compute[1-10]``.
+
+ Terms may optionally be joined with boolean operators and parenthesis to
+ allow the formation of more complex constraints or queries.
+
+ Boolean operators include logical AND (``&``, ``&&``, or ``and``), logical OR
+ (``|``, ``||``, or ``or``), and logical negation (``not``).
+
+ Terms separated by whitespace are joined with logical AND by default.
+
+ Quoting of terms is supported to allow whitespace and other reserved
+ characters in operand, e.g. ``foo:'this is args'``.
+
+ Negation is supported in front of terms such that ``-op:operand`` is
+ equivalent to ``not op:operand``. Negation is not supported in front of
+ general expressions, e.g. ``-(a|b)`` is a syntax error.
+
+ The full specification of Constraint Query Syntax can be found in RFC 35.
+
+ Currently, :option:`--requires` supports the following operators:
+
+ properties
+ Require the set of specified properties. Properties may be
+ comma-separated, in which case all specified properties are required.
+ As a convenience, if a property starts with ``^`` then a matching
+ resource must not have the specified property. In these commands,
+ the ``properties`` operator is the default, so that ``a,b`` is equivalent
+ to ``properties:a,b``.
+
+ hostlist
+ Require matching resources to be in the specified hostlist (in RFC
+ 29 format). ``host`` or ``hosts`` is also accepted.
+
+ ranks
+ Require matching resources to be on the specified broker ranks in
+ RFC 22 Idset String Representation.
+
+ Examples:
+
+ ``a b c``, ``a&b&c``, or ``a,b,c``
+ Require properties a and b and c.
+
+ ``a|b|c``, or ``a or b or c``
+ Require property a or b or c.
+
+ ``(a and b) or (b and c)``
+ Require properties a and b or b and c.
+
+ ``b|-c``, ``b or not c``
+ Require property b or not c.
+
+ ``host:fluke[1-5]``
+ Require host in fluke1 through fluke5.
+
+ ``-host:fluke7``
+ Exclude host fluke7.
+
+ ``rank:0``
+ Require broker rank 0.
+
+
diff --git a/doc/man1/common/job-dependencies.rst b/doc/man1/common/job-dependencies.rst
new file mode 100644
index 000000000000..09007c68e3e9
--- /dev/null
+++ b/doc/man1/common/job-dependencies.rst
@@ -0,0 +1,71 @@
+.. note::
+ Flux supports a simple but powerful job dependency specification in jobspec.
+ See Flux Framework RFC 26 for more detailed information about the generic
+ dependency specification.
+
+Dependencies may be specified on the command line using the following options:
+
+.. option:: --dependency=URI
+
+ Specify a dependency of the submitted job using RFC 26 dependency URI
+ format. The URI format is **SCHEME:VALUE[?key=val[&key=val...]]**.
+ The URI will be converted into RFC 26 JSON object form and appended to
+ the jobspec ``attributes.system.dependencies`` array. If the current
+ Flux instance does not support dependency scheme *SCHEME*, then the
+ submitted job will be rejected with an error message indicating this
+ fact.
+
+ The :option:`--dependency` option may be specified multiple times. Each use
+ appends a new dependency object to the ``attributes.system.dependencies``
+ array.
+
+The following dependency schemes are built-in:
+
+.. note::
+ The ``after*`` dependency schemes listed below all require that the
+ target JOBID be currently active or in the job manager's inactive job
+ cache. If a target JOBID has been purged by the time the dependent job
+ has been submitted, then the submission will be rejected with an error
+ that the target job cannot be found.
+
+after:JOBID
+ This dependency is satisfied after JOBID starts.
+
+afterany:JOBID
+ This dependency is satisfied after JOBID enters the INACTIVE state,
+ regardless of the result
+
+afterok:JOBID
+ This dependency is satisfied after JOBID enters the INACTIVE state
+ with a successful result.
+
+afternotok:JOBID
+ This dependency is satisfied after JOBID enters the INACTIVE state
+ with an unsuccessful result.
+
+begin-time:TIMESTAMP
+ This dependency is satisfied after TIMESTAMP, which is specified in
+ floating point seconds since the UNIX epoch. See the ``--begin-time``
+ option below for a more user-friendly interface to the ``begin-time``
+ dependency.
+
+In any of the above ``after*`` cases, if it is determined that the
+dependency cannot be satisfied (e.g. a job fails due to an exception
+with afterok), then a fatal exception of type=dependency is raised
+on the current job. An example of submitting a job, getting the Flux
+job identifier, and then submitting a job that depends on it (meaning
+it will wait for completion before starting) is provided below:
+
+.. code-block:: console
+
+ # Do some long work
+ jobid=$(flux submit -N2 sleep 200)
+
+ # Submit the dependent job
+ flux submit --dependency=afterany:$jobid /bin/bash my-script.sh
+
+ # Look at your queue
+ flux jobs -a
+
+ # Block and watch output
+ flux job attach $(flux job last)
diff --git a/doc/man1/common/job-env-rules.rst b/doc/man1/common/job-env-rules.rst
new file mode 100644
index 000000000000..acfa0209e50e
--- /dev/null
+++ b/doc/man1/common/job-env-rules.rst
@@ -0,0 +1,86 @@
+The `ENVIRONMENT`_ options allow control of the environment exported to jobs
+via a set of *RULE* expressions. The currently supported rules are
+
+ * If a rule begins with ``-``, then the rest of the rule is a pattern
+ which removes matching environment variables. If the pattern starts
+ with ``/``, it is a :linux:man7:`regex`, optionally ending with
+ ``/``, otherwise the pattern is considered a shell
+ :linux:man7:`glob` expression.
+
+ Examples:
+ ``-*`` or ``-/.*/`` filter all environment variables creating an
+ empty environment.
+
+ * If a rule begins with ``^`` then the rest of the rule is a filename
+ from which to read more rules, one per line. The ``~`` character is
+ expanded to the user's home directory.
+
+ Examples:
+ ``~/envfile`` reads rules from file ``$HOME/envfile``
+
+ * If a rule is of the form ``VAR=VAL``, the variable ``VAR`` is set
+ to ``VAL``. Before being set, however, ``VAL`` will undergo simple
+ variable substitution using the Python ``string.Template`` class. This
+ simple substitution supports the following syntax:
+
+ * ``$$`` is an escape; it is replaced with ``$``
+ * ``$var`` will substitute :envvar:`var` from the current environment,
+ falling back to the process environment. An error will be thrown
+ if environment variable :envvar:`var` is not set.
+ * ``${var}`` is equivalent to ``$var``
+ * Advanced parameter substitution is not allowed, e.g. ``${var:-foo}``
+ will raise an error.
+
+ Examples:
+ ``PATH=/bin``, ``PATH=$PATH:/bin``, ``FOO=${BAR}something``
+
+ * Otherwise, the rule is considered a pattern from which to match
+ variables from the process environment if they do not exist in
+ the generated environment. E.g. ``PATH`` will export :envvar:`PATH` from the
+ current environment (if it has not already been set in the generated
+ environment), and ``OMP*`` would copy all environment variables that
+ start with :envvar:`OMP` and are not already set in the generated
+ environment. It is important to note that if the pattern does not match
+ any variables, then the rule is a no-op, i.e. an error is *not* generated.
+
+ Examples:
+ ``PATH``, ``FLUX_*_PATH``, ``/^OMP.*/``
+
+Since we always starts with a copy of the current environment,
+the default implicit rule is ``*`` (or :option:`--env=*`). To start with an
+empty environment instead, the ``-*`` rule or :option:`--env-remove=*` option
+should be used. For example, the following will only export the current
+:envvar:`PATH` to a job:
+
+::
+
+ flux run --env-remove=* --env=PATH ...
+
+
+Since variables can be expanded from the currently built environment, and
+:option:`--env` options are applied in the order they are used, variables can
+be composed on the command line by multiple invocations of :option:`--env`,
+e.g.:
+
+::
+
+ flux run --env-remove=* \
+ --env=PATH=/bin --env='PATH=$PATH:/usr/bin' ...
+
+Note that care must be taken to quote arguments so that ``$PATH`` is not
+expanded by the shell.
+
+
+This works particularly well when specifying rules in a file:
+
+::
+
+ -*
+ OMP*
+ FOO=bar
+ BAR=${FOO}/baz
+
+The above file would first clear the environment, then copy all variables
+starting with :envvar:`OMP` from the current environment, set ``FOO=bar``,
+and then set ``BAR=bar/baz``.
+
diff --git a/doc/man1/common/job-environment-variables.rst b/doc/man1/common/job-environment-variables.rst
new file mode 100644
index 000000000000..2fabf241fb92
--- /dev/null
+++ b/doc/man1/common/job-environment-variables.rst
@@ -0,0 +1,26 @@
+.. list-table::
+ :header-rows: 1
+
+ * - Name
+ - Description
+
+ * - :envvar:`FLUX_JOB_ID`
+ - the current jobid
+
+ * - :envvar:`FLUX_JOB_SIZE`
+ - the number of tasks in the current job
+
+ * - :envvar:`FLUX_JOB_NNODES`
+ - the total number of nodes hosting tasks on behalf of the job
+
+ * - :envvar:`FLUX_TASK_RANK`
+ - the global task rank (zero origin)
+
+ * - :envvar:`FLUX_TASK_LOCAL_ID`
+ - the local task rank (zero origin)
+
+ * - :envvar:`FLUX_JOB_TMPDIR`
+ - path to temporary, per-job directory, usually in ``/tmp``
+
+ * - :envvar:`FLUX_URI`
+ - the URI of the enclosing Flux instance
diff --git a/doc/man1/common/job-environment.rst b/doc/man1/common/job-environment.rst
new file mode 100644
index 000000000000..f04a0482ff46
--- /dev/null
+++ b/doc/man1/common/job-environment.rst
@@ -0,0 +1,20 @@
+.. option:: --env=RULE
+
+ Control how environment variables are exported with *RULE*. See
+ the `ENV RULES`_ section below for more information. Rules are
+ applied in the order in which they are used on the command line.
+ This option may be specified multiple times.
+
+.. option:: --env-remove=PATTERN
+
+ Remove all environment variables matching *PATTERN* from the current
+ generated environment. If *PATTERN* starts with a ``/`` character,
+ then it is considered a :linux:man7:`regex`, otherwise *PATTERN* is
+ treated as a shell :linux:man7:`glob`. This option is equivalent to
+ :option:`--env=-PATTERN` and may be used multiple times.
+
+.. option:: --env-file=FILE
+
+ Read a set of environment *RULES* from a *FILE*. This option is
+ equivalent to :option:`--env=^FILE` and may be used multiple times.
+
diff --git a/doc/man1/common/job-other-batch.rst b/doc/man1/common/job-other-batch.rst
new file mode 100644
index 000000000000..502428e5121f
--- /dev/null
+++ b/doc/man1/common/job-other-batch.rst
@@ -0,0 +1,73 @@
+.. option:: --conf=FILE|KEY=VAL|STRING|NAME
+
+ The :option:`--conf`` option allows configuration for a Flux instance
+ started via ``flux-batch(1)`` or ``flux-alloc(1)`` to be iteratively built
+ on the command line. On first use, a ``conf.json`` entry is added to the
+ internal jobspec file archive, and ``-c{{tmpdir}}/conf.json`` is added
+ to the flux broker command line. Each subsequent use of the :option:`--conf`
+ option updates this configuration.
+
+ The argument to :option:`--conf` may be in one of several forms:
+
+ * A multiline string, e.g. from a batch directive. In this case the string
+ is parsed as JSON or TOML::
+
+ # flux: --conf="""
+ # flux: [resource]
+ # flux: exclude = "0"
+ # flux: """
+
+ * A string containing a ``=`` character, in which case the argument is
+ parsed as ``KEY=VAL``, where ``VAL`` is parsed as JSON, e.g.::
+
+ --conf=resource.exclude=\"0\"
+
+ * A string ending in ``.json`` or ``.toml``, in which case configuration
+ is loaded from a JSON or TOML file.
+
+ * If none of the above conditions match, then the argument ``NAME`` is
+ assumed to refer to a "named" config file ``NAME.toml`` or ``NAME.json``
+ within the following search path, in order of precedence:
+
+ - ``XDG_CONFIG_HOME/flux/config`` or ``$HOME/.config/flux/config`` if
+ :envvar:`XDG_CONFIG_HOME` is not set
+
+ - ``$XDG_CONFIG_DIRS/flux/config`` or ``/etc/xdg/flux/config`` if
+ :envvar:`XDG_CONFIG_DIRS` is not set. Note that :envvar:`XDG_CONFIG_DIRS`
+ may be a colon-separated path.
+
+.. option:: --bg
+
+ *(alloc only)* Do not interactively attach to the instance. Instead,
+ print jobid on stdout once the instance is ready to accept jobs. The
+ instance will run indefinitely until a time limit is reached, the
+ job is canceled, or it is shutdown with ``flux shutdown JOBID``
+ (preferred). If a COMMAND is given then the job will run until COMMAND
+ completes. Note that ``flux job attach JOBID`` cannot be used to
+ interactively attach to the job (though it will print any errors or
+ output).
+
+.. option:: -B, --broker-opts=OPT
+
+ Pass specified options to the Flux brokers of the new instance. This
+ option may be specified multiple times.
+
+.. option:: --wrap
+
+ *(batch only)* The :option:`--wrap` option wraps the specified COMMAND and
+ ARGS in a shell script, by prefixing with ``#!/bin/sh``. If no COMMAND is
+ present, then a SCRIPT is read on stdin and wrapped in a /bin/sh script.
+
+.. option:: --dump=[FILE]
+
+ When the job script is complete, archive the Flux
+ instance's KVS content to ``FILE``, which should have a suffix known
+ to :linux:man3:`libarchive`, and may be a mustache template as described
+ above for :option:`--output`. The content may be unarchived directly or
+ examined within a test instance started with the
+ :option:`flux-start --recovery` option. If ``FILE`` is unspecified,
+ ``flux-{{jobid}}-dump.tgz`` is used.
+
+.. option:: --quiet
+
+ Suppress logging of jobids to stdout
diff --git a/doc/man1/common/job-other-options.rst b/doc/man1/common/job-other-options.rst
new file mode 100644
index 000000000000..a5298fc13413
--- /dev/null
+++ b/doc/man1/common/job-other-options.rst
@@ -0,0 +1,120 @@
+.. option:: --cwd=DIRECTORY
+
+ Set job working directory.
+
+.. option:: --urgency=N
+
+ Specify job urgency. *N* has a range of 0 to 16 for guest users, 0 to 31
+ for instance owners, and a default value of 16. In addition to numerical
+ values, the following special names are accepted:
+
+ hold (0)
+ Hold the job until the urgency is raised with :option:`flux job urgency`.
+
+ default (16)
+ The default urgency for all users.
+
+ expedite (31)
+ Assign the highest possible priority to the job (restricted to instance
+ owner).
+
+ Urgency is one factor used to calculate job priority, which affects the
+ order in which the scheduler considers jobs. By default, priority is
+ calculated from the urgency and the time elapsed since job submission.
+ This calculation may be overridden by configuration. For example, in a
+ multi-user Flux instance with the Flux accounting priority plugin loaded,
+ the calculation includes other factors such as past usage and bank
+ allocations.
+
+ A job with an urgency value of 0 is treated specially: it is never
+ considered by the scheduler and is effectively *held*. Similarly, a job
+ with an urgency of 31 is always assigned the maximum priority, regardless
+ of other factors and is considered *expedited*.
+
+ :option:`flux jobs -o deps` lists jobs with urgency and priority fields.
+
+.. option:: -v, --verbose
+
+ Increase verbosity on stderr. For example,
+ currently :option:`flux run -v` displays jobid, :option:`-vv` displays job
+ events, and :option:`-vvv` displays exec events. :option:`flux alloc -v`
+ forces the command to print the submitted jobid on stderr. The specific
+ output may change in the future.
+
+.. option:: -o, --setopt=KEY[=VAL]
+
+ Set shell option. Keys may include periods to denote hierarchy.
+ VAL is optional and may be valid JSON (bare values, objects, or arrays),
+ otherwise VAL is interpreted as a string. If VAL is not set, then the
+ default value is 1. See `SHELL OPTIONS`_ below.
+
+.. option:: -S, --setattr=KEY[=VAL]
+
+ Set jobspec attribute. Keys may include periods to denote hierarchy.
+ If KEY does not begin with ``system.``, ``user.``, or ``.``, then
+ ``system.`` is assumed. VAL is optional and may be valid JSON (bare
+ values, objects, or arrays), otherwise VAL is interpreted as a string. If
+ VAL is not set, then the default value is 1. If KEY starts with a ``^``
+ character, then VAL is interpreted as a file, which must be valid JSON,
+ to use as the attribute value.
+
+.. option:: --add-file=[NAME[:PERMS]=]ARG
+
+ Add a file to the RFC 37 file archive in jobspec before submission. Both
+ the file metadata and content are stored in the archive, so modification
+ or deletion of a file after being processed by this option will have no
+ effect on the job. If no ``NAME`` is provided, then ``ARG`` is assumed
+ to be the path to a local file and the basename of the file will be
+ used as ``NAME``. Otherwise, if ``ARG`` contains a newline, then it
+ is assumed to be the raw file data to encode. If ``PERMS`` is provided
+ and is a valid octal integer, then this will override the default file
+ permissions of 0600. The file will be extracted by the job shell into
+ the job temporary directory and may be referenced as ``{{tmpdir}}/NAME``
+ on the command line, or ``$FLUX_JOB_TMPDIR/NAME`` in a batch script.
+ This option may be specified multiple times to encode multiple files.
+ Note: As documented in RFC 14, the file names ``script`` and ``conf.json``
+ are both reserved.
+
+ .. note::
+ This option should only be used for small files such as program input
+ parameters, configuration, scripts, and so on. For broadcast of large
+ files, binaries, and directories, the :man1:`flux-shell` ``stage-in``
+ plugin will be more appropriate.
+
+.. option:: --begin-time=+FSD|DATETIME
+
+ Convenience option for setting a ``begin-time`` dependency for a job.
+ The job is guaranteed to start after the specified date and time.
+ If argument begins with a ``+`` character, then the remainder is
+ considered to be an offset in Flux standard duration (RFC 23), otherwise,
+ any datetime expression accepted by the Python
+ `parsedatetime `_ module
+ is accepted, e.g. ``2021-06-21 8am``, ``in an hour``,
+ ``tomorrow morning``, etc.
+
+.. option:: --signal=SIG@TIME
+
+ Send signal ``SIG`` to job ``TIME`` before the job time limit. ``SIG``
+ can specify either an integer signal number or a full or abbreviated
+ signal name, e.g. ``SIGUSR1`` or ``USR1`` or ``10``. ``TIME`` is
+ specified in Flux Standard Duration, e.g. ``30`` for 30s or ``1h`` for
+ 1 hour. Either parameter may be omitted, with defaults of ``SIGUSR1``
+ and 60s. For example, :option:`--signal=USR2` will send ``SIGUSR2`` to
+ the job 60 seconds before expiration, and :option:`--signal=@3m` will send
+ ``SIGUSR1`` 3 minutes before expiration. Note that if ``TIME`` is
+ greater than the remaining time of a job as it starts, the job will
+ be signaled immediately.
+
+ The default behavior is to not send any warning signal to jobs.
+
+.. option:: --dry-run
+
+ Don't actually submit job. Just emit jobspec on stdout and exit for
+ ``run``, ``submit``, ``alloc``, and ``batch``. For ``bulksubmit``,
+ emit a line of output including relevant options for each job which
+ would have been submitted,
+
+.. option:: --debug
+
+ Enable job debug events, primarily for debugging Flux itself.
+ The specific effects of this option may change in the future.
diff --git a/doc/man1/common/job-other-run.rst b/doc/man1/common/job-other-run.rst
new file mode 100644
index 000000000000..57c92ea20c49
--- /dev/null
+++ b/doc/man1/common/job-other-run.rst
@@ -0,0 +1,111 @@
+.. option:: --taskmap=SCHEME[:VALUE]
+
+ Choose an alternate method for mapping job task IDs to nodes of the
+ job. The job shell maps tasks using a "block" distribution scheme by
+ default (consecutive tasks share nodes) This option allows the
+ activation of alternate schemes by name, including an optional *VALUE*.
+ Supported schemes which are built in to the job shell include
+
+ cyclic[:N]
+ Tasks are distributed over consecutive nodes with a stride of *N*
+ (where N=1 by default).
+
+ manual:TASKMAP
+ An explicit RFC 34 taskmap is provided and used to manually map
+ task ids to nodes. The provided *TASKMAP* must match the total number
+ of tasks in the job and the number of tasks per node assigned by
+ the job shell, so this option is not useful unless the total number
+ of nodes and tasks per node are known at job submission time.
+
+ hostfile:FILE
+ Assign tasks in order to hosts as they appear in FILE. FILE should
+ have one or more lines each of which contains a host name or RFC
+ 29 Hostlist string. Each host assigned to the job must appear in
+ the hostfile and be assigned the same number of tasks as the default
+ taskmap from the shell. If there are less hosts in the hostfile than
+ tasks in the job, then the list of hosts will be reused.
+
+ However, shell plugins may provide other task mapping schemes, so
+ check the current job shell configuration for a full list of supported
+ taskmap schemes.
+
+.. option:: --cc=IDSET
+
+ *(submit,bulksubmit)* Replicate the job for each ``id`` in ``IDSET``.
+ :envvar:`FLUX_JOB_CC` will be set to ``id`` in the environment of each
+ submitted job to allow the job to alter its execution based on the
+ submission index. (e.g. for reading from a different input file). When
+ using :option:`--cc`, the substitution string ``{cc}`` may be used in
+ options and commands and will be replaced by the current ``id``.
+
+.. option:: --bcc=IDSET
+
+ *(submit,bulksubmit)* Identical to :option:`--cc`, but do not set
+ :envvar:`FLUX_JOB_CC` in each job. All jobs will be identical copies.
+ As with :option:`--cc`, ``{cc}`` in option arguments and commands will be
+ replaced with the current ``id``.
+
+.. option:: --quiet
+
+ Suppress logging of jobids to stdout
+
+.. option:: --log=FILE
+
+ *(submit,bulksubmit)* Log command output and stderr to ``FILE``
+ instead of the terminal. If a replacement (e.g. ``{}`` or ``{cc}``)
+ appears in ``FILE``, then one or more output files may be opened.
+ For example, to save all submitted jobids into separate files, use::
+
+ flux submit --cc=1-4 --log=job{cc}.id hostname
+
+.. option:: --log-stderr=FILE
+
+ *(submit,bulksubmit)* Separate stderr into ``FILE`` instead of sending
+ it to the terminal or a ``FILE`` specified by :option:`--log`.
+
+.. option:: --wait
+
+ *(submit,bulksubmit)* Wait on completion of all jobs before exiting.
+ This is equivalent to :option:`--wait-event=clean`.
+
+.. option:: --wait-event=NAME
+
+ Wait until job or jobs have received event ``NAME``
+ before exiting. E.g. to submit a job and block until the job begins
+ running, use :option:`--wait-event=start`. *(submit,bulksubmit only)* If
+ ``NAME`` begins with ``exec.``, then wait for an event in the exec eventlog,
+ e.g. ``exec.shell.init``. For ``flux run`` the argument to this option
+ when used is passed directly to ``flux job attach``.
+
+.. option:: --watch
+
+ *(submit,bulksubmit)* Display output from all jobs. Implies :option:`--wait`.
+
+.. option:: --progress
+
+ *(submit,bulksubmit)* With :option:`--wait`, display a progress bar showing
+ the progress of job completion. Without :option:`--wait`, the progress bar
+ will show progress of job submission.
+
+.. option:: --jps
+
+ *(submit,bulksubmit)* With :option:`--progress`, display throughput
+ statistics (jobs/s) in the progress bar.
+
+.. option:: --define=NAME=CODE
+
+ *(bulksubmit)* Define a named method that will be made available as an
+ attribute during command and option replacement. The string being
+ processed is available as ``x``. For example::
+
+ $ seq 1 8 | flux bulksubmit --define=pow="2**int(x)" -n {.pow} ...
+
+.. option:: --shuffle
+
+ *(bulksubmit)* Shuffle the list of commands before submission.
+
+.. option:: --sep=STRING
+
+ *(bulksubmit)* Change the separator for file input. The default is
+ to separate files (including stdin) by newline. To separate by
+ consecutive whitespace, specify :option:`--sep=none`.
diff --git a/doc/man1/common/job-param-additional.rst b/doc/man1/common/job-param-additional.rst
new file mode 100644
index 000000000000..30815fe28900
--- /dev/null
+++ b/doc/man1/common/job-param-additional.rst
@@ -0,0 +1,42 @@
+.. option:: -q, --queue=NAME
+
+ Submit a job to a specific named queue. If a queue is not specified
+ and queues are configured, then the jobspec will be modified at ingest
+ to specify the default queue. If queues are not configured, then this
+ option is ignored, though :man1:`flux-jobs` may display the queue
+ name in its rendering of the ``{queue}`` attribute.
+
+.. option:: -B, --bank=NAME
+
+ Set the bank name for this job to ``NAME``. This option is equivalent
+ to `--setattr=bank=NAME`, and results in the ``bank`` attribute being
+ set to ``NAME`` in the submitted jobspec. However, besides the bank
+ name appearing in job listing output, this option may have no effect
+ if no plugin or package that supports it (such as flux-accounting)
+ is installed and configured.
+
+.. option:: -t, --time-limit=MINUTES|FSD
+
+ Set a time limit for the job in either minutes or Flux standard duration
+ (RFC 23). FSD is a floating point number with a single character units
+ suffix ("s", "m", "h", or "d"). The default unit for the
+ :option:`--time-limit` option is minutes when no units are otherwise
+ specified. If the time limit is unspecified, the job is subject to the
+ system default time limit.
+
+.. option:: --job-name=NAME
+
+ Set an alternate job name for the job. If not specified, the job name
+ will default to the command or script executed for the job.
+
+.. option:: --flags=FLAGS
+
+ Set comma separated list of job submission flags. The possible flags are
+ ``waitable``, ``novalidate``, and ``debug``. The ``waitable`` flag will
+ allow the job to be waited on via ``flux job wait`` and similar API calls.
+ The ``novalidate`` flag will inform flux to skip validation of a job's
+ specification. This may be useful for high throughput ingest of a large
+ number of jobs. Both ``waitable`` and ``novalidate`` require instance
+ owner privileges. ``debug`` will output additional debugging into the job
+ eventlog.
+
diff --git a/doc/man1/common/job-param-batch.rst b/doc/man1/common/job-param-batch.rst
new file mode 100644
index 000000000000..04fa228b6a9a
--- /dev/null
+++ b/doc/man1/common/job-param-batch.rst
@@ -0,0 +1,20 @@
+.. option:: -n, --nslots=N
+
+ Set the number of slots requested. This parameter is required unless
+ :option:`--nodes` is specified.
+
+.. option:: -c, --cores-per-slot=N
+
+ Set the number of cores to assign to each slot (default 1).
+
+.. option:: -g, --gpus-per-slot=N
+
+ Set the number of GPU devices to assign to each slot (default none).
+
+.. option:: -N, --nodes=N
+
+ Distribute allocated resource slots across *N* individual nodes.
+
+.. option:: -x, --exclusive
+
+ With :option:`--nodes`, allocate nodes exclusively.
diff --git a/doc/man1/common/job-param-common.rst b/doc/man1/common/job-param-common.rst
new file mode 100644
index 000000000000..fd1c182dfb8f
--- /dev/null
+++ b/doc/man1/common/job-param-common.rst
@@ -0,0 +1,16 @@
+.. option:: -N, --nodes=N
+
+ Set the number of nodes to assign to the job. Tasks will be distributed
+ evenly across the allocated nodes, unless the per-resource options
+ (noted below) are used with *submit*, *run*, or *bulksubmit*. It is
+ an error to request more nodes than there are tasks. If unspecified,
+ the number of nodes will be chosen by the scheduler.
+
+.. option:: -x, --exclusive
+
+ Indicate to the scheduler that nodes should be exclusively allocated to
+ this job. It is an error to specify this option without also using
+ :option:`--nodes`. If :option:`--nodes` is specified without
+ :option:`--nslots` or :option:`--ntasks`, then this option will be enabled
+ by default and the number of tasks or slots will be set to the number of
+ requested nodes.
diff --git a/doc/man1/common/job-param-perres.rst b/doc/man1/common/job-param-perres.rst
new file mode 100644
index 000000000000..cab18659406d
--- /dev/null
+++ b/doc/man1/common/job-param-perres.rst
@@ -0,0 +1,20 @@
+.. option:: --cores=N
+
+ Set the total number of cores.
+
+.. option:: --tasks-per-node=N
+
+ Set the number of tasks per node to run.
+
+.. option:: --gpus-per-node=N
+
+ With :option:`--nodes`, request a specific number of GPUs per node.
+
+.. option:: --tasks-per-core=N
+
+ Force a number of tasks per core. Note that this will run *N* tasks per
+ *allocated* core. If nodes are exclusively scheduled by configuration or
+ use of the :option:`--exclusive` flag, then this option could result in many
+ more tasks than expected. The default for this option is effectively 1,
+ so it is useful only for oversubscribing tasks to cores for testing
+ purposes. You probably don't want to use this option.
diff --git a/doc/man1/common/job-param-pertask.rst b/doc/man1/common/job-param-pertask.rst
new file mode 100644
index 000000000000..153e75e7ead1
--- /dev/null
+++ b/doc/man1/common/job-param-pertask.rst
@@ -0,0 +1,11 @@
+.. option:: -n, --ntasks=N
+
+ Set the number of tasks to launch (default 1).
+
+.. option:: -c, --cores-per-task=N
+
+ Set the number of cores to assign to each task (default 1).
+
+.. option:: -g, --gpus-per-task=N
+
+ Set the number of GPU devices to assign to each task (default none).
diff --git a/doc/man1/common/job-process-resource-limits.rst b/doc/man1/common/job-process-resource-limits.rst
new file mode 100644
index 000000000000..d3ac3e6dda72
--- /dev/null
+++ b/doc/man1/common/job-process-resource-limits.rst
@@ -0,0 +1,41 @@
+.. option:: --rlimit=RULE
+
+ Control how process resource limits are propagated with *RULE*. Rules
+ are applied in the order in which they are used on the command line.
+ This option may be used multiple times.
+
+The :option:`--rlimit` rules work similar to the :option:`--env` option rules:
+
+ * If a rule begins with ``-``, then the rest of the rule is a name or
+ :linux:man7:`glob` pattern which removes matching resource limits from
+ the set to propagate.
+
+ Example:
+ ``-*`` disables propagation of all resource limits.
+
+ * If a rule is of the form ``LIMIT=VALUE`` then *LIMIT* is explicitly
+ set to *VALUE*. If *VALUE* is ``unlimited``, ``infinity`` or ``inf``,
+ then the value is set to ``RLIM_INFINITY`` (no limit).
+
+ Example:
+ ``nofile=1024`` overrides the current ``RLIMIT_NOFILE`` limit to 1024.
+
+ * Otherwise, *RULE* is considered a pattern from which to match resource
+ limits and propagate the current limit to the job, e.g.
+
+ ``--rlimit=memlock``
+
+ will propagate ``RLIMIT_MEMLOCK`` (which is not in the list of limits
+ that are propagated by default).
+
+We start with a default list of resource limits to propagate,
+then applies all rules specified via :option:`--rlimit` on the command line.
+Therefore, to propagate only one limit, ``-*`` should first be used to
+start with an empty set, e.g. :option:`--rlimit=-*,core` will only propagate
+the ``core`` resource limit.
+
+The set of resource limits propagated by default includes all those except
+``memlock``, ``ofile``, ``msgqueue``, ``nice``, ``rtprio``, ``rttime``,
+and ``sigpending``. To propagate all possible resource limits, use
+:option:`--rlimit=*`.
+
diff --git a/doc/man1/common/job-shell-options.rst b/doc/man1/common/job-shell-options.rst
new file mode 100644
index 000000000000..1efb6e5f55ef
--- /dev/null
+++ b/doc/man1/common/job-shell-options.rst
@@ -0,0 +1,58 @@
+.. Once we advance to sphinx 5.3+, :option: will x-ref with arguments
+.. e.g. :option:`cpu-affinity=OFF`. For now, leave options off to get x-ref.
+
+.. list-table::
+ :header-rows: 1
+
+ * - Name
+ - Description
+
+ * - :option:`cpu-affinity`
+ - Set task affinity to cores (:option:`off|per-task|map:LIST|on`)
+
+ * - :option:`gpu-affinity`
+ - Set task affinity to GPUs (:option:`off|per-task|map:LIST|on`)
+
+ * - :option:`verbose`
+ - Increase shell log verbosity (1 or 2).
+
+ * - :option:`nosetpgrp`
+ - Don't run each task in its own process group.
+
+ * - :option:`pmi`
+ - Set PMI service(s) for launched programs (:option:`off|simple|LIST`)
+
+ * - :option:`stage-in`
+ - Copy files previously mapped with :man1:`flux-archive` to
+ :envvar:`FLUX_JOB_TMPDIR`.
+
+ * - :option:`pty.interactive`
+ - Enable a pty on rank 0 for :program:`flux job attach`.
+
+ * - :option:`exit-timeout`
+ - Start fatal job exception timer after first task exits
+ (:option:`none|FSD`)
+
+ * - :option:`exit-on-error`
+ - Raise a fatal job exception immediately if first task exits with
+ nonzero exit code.
+
+ * - :option:`hwloc.xmlfile`
+ - Write hwloc XML gathered by job to a file and set ``HWLOC_XMLFILE``.
+ Note that this option will also unset ``HWLOC_COMPONENTS`` if set, since
+ presence of this environment variable may cause hwloc to ignore
+ ``HWLOC_XMLFILE``.
+
+ * - :option:`hwloc.restrict`
+ - With :option:`hwloc.xmlfile`, restrict the exported topology XML to only
+ those resources assigned to the current job. By default, the XML is
+ not restricted.
+
+ * - :option:`output.limit`
+ - Set KVS output limit to SIZE bytes, where SIZE may be a floating point
+ value including optional SI units: k, K, M, G. This value is ignored
+ if output is directed to a file with :option:`--output`.
+
+ * - :option:`output.mode`
+ - Set the open mode for output files to either "truncate" or "append".
+ The default is "truncate".
diff --git a/doc/man1/common/job-standard-io.rst b/doc/man1/common/job-standard-io.rst
new file mode 100644
index 000000000000..0650e5a06e71
--- /dev/null
+++ b/doc/man1/common/job-standard-io.rst
@@ -0,0 +1,56 @@
+.. note::
+ Paths specified in the options :option:`--output`, :option:`--error`,
+ and :option:`--input` will be opened relative to the working directory
+ on the first node of the job allocation, not on the node from which
+ the job is submitted.
+
+.. option:: --input=FILENAME|RANKS
+
+ Redirect stdin to the specified filename, bypassing the KVS.
+ As a special case for ``flux run``, the argument may specify
+ an idset of task ranks in to which to direct standard input.
+
+.. option:: --output=TEMPLATE
+
+ Specify the filename *TEMPLATE* for stdout redirection, bypassing
+ the KVS. *TEMPLATE* may be a mustache template which supports the
+ following tags:
+
+ *{{id}}* or *{{jobid}}*
+ Expands to the current jobid in the F58 encoding. If needed, an
+ alternate encoding may be selected by using a subkey with the name
+ of the desired encoding, e.g. *{{id.dec}}*. Supported encodings
+ include *f58* (the default), *dec*, *hex*, *dothex*, and *words*.
+
+ *{{name}}*
+ Expands to the current job name. If a name is not set for the job,
+ then the basename of the command will be used.
+
+.. option:: --error=TEMPLATE
+
+ Redirect stderr to the specified filename *TEMPLATE*, bypassing the KVS.
+ *TEMPLATE* is expanded as described above.
+
+.. option:: -u, --unbuffered
+
+ Disable buffering of standard input and output as much as practical.
+ Normally, stdout from job tasks is line buffered, as is stdin when
+ running a job in the foreground via :man1:`flux-run`. Additionally,
+ job output may experience a delay due to batching of output
+ events by the job shell. With the :option:`--unbuffered` option,
+ ``output.*.buffer.type=none`` is set in jobspec to request no buffering
+ of output, and the default output batch period is reduced greatly,
+ to make output appear in the KVS and printed to the standard output
+ of :man1:`flux-run` as soon as possible. The :option:`--unbuffered` option
+ is also passed to ``flux job attach``, which makes stdin likewise
+ unbuffered. Note that the application and/or terminal may have
+ additional input and output buffering which this option will not
+ affect. For instance, by default an interactive terminal in canonical
+ input mode will process input by line only. Likewise, stdout of a
+ process run without a terminal may be fully buffered when using
+ libc standard I/O streams (See NOTES in :linux:man3:`stdout`).
+
+.. option:: -l, --label-io
+
+ Add task rank prefixes to each line of output.
+
diff --git a/doc/man1/common/resources.rst b/doc/man1/common/resources.rst
new file mode 100644
index 000000000000..dcc16e8954b0
--- /dev/null
+++ b/doc/man1/common/resources.rst
@@ -0,0 +1,5 @@
+Flux: http://flux-framework.org
+
+Flux RFC: https://flux-framework.readthedocs.io/projects/flux-rfc
+
+Issue Tracker: https://github.com/flux-framework/flux-core/issues
diff --git a/doc/man1/flux-alloc.rst b/doc/man1/flux-alloc.rst
new file mode 100644
index 000000000000..b055416e04ed
--- /dev/null
+++ b/doc/man1/flux-alloc.rst
@@ -0,0 +1,145 @@
+.. flux-help-include: true
+.. flux-help-section: submission
+
+=============
+flux-alloc(1)
+=============
+
+SYNOPSIS
+========
+
+**flux** **alloc** [OPTIONS] [COMMAND...]
+
+DESCRIPTION
+===========
+
+.. program:: flux alloc
+
+:program:`flux alloc` runs a Flux subinstance with *COMMAND* as the initial
+program. Once resources are allocated, *COMMAND* executes on the first node of
+the allocation with any free arguments supplied as *COMMAND* arguments. When
+*COMMAND* exits, the Flux subinstance exits, resources are released to the
+enclosing Flux instance, and :program:`flux alloc` returns.
+
+If no *COMMAND* is specified, an interactive shell is spawned as the initial
+program, and the subinstance runs until the shell is exited.
+
+If the :option:`--bg` option is specified, the subinstance runs without an
+initial program. :program:`flux alloc` prints the jobid and returns as soon as
+the subinstance is ready to accept jobs. The subinstance runs until it exceeds
+its time limit, is canceled, or is shut down with :man1:`flux-shutdown`.
+
+Flux commands that are run from the subinstance (e.g. from the interactive
+shell) refer to the subinstance. For example, :man1:`flux-run` would launch
+work there. A Flux command run from the subinstance can be forced to refer
+to the enclosing instance by supplying the :option:`flux --parent` option.
+
+Flux commands outside of the subinstance refer to their enclosing instance,
+often a system instance. :man1:`flux-proxy` establishes a connection to a
+running subinstance by jobid, then spawns a shell in which Flux commands
+refer to the subinstance, for example
+
+::
+
+ $ flux alloc --bg -N 2 --queue=batch
+ ÆM7Zq9AKHno
+ $ flux proxy ÆM7Zq9AKHno
+ $ flux run -n16 ./testprog
+ ...
+ $ flux shutdown
+ ...
+ $
+
+The available OPTIONS are detailed below.
+
+JOB PARAMETERS
+==============
+
+:program:`flux batch` and :program:`flux alloc` do not launch tasks directly,
+and therefore job parameters are normally specified in terms of resource slot
+size and number of slots. A resource slot can be thought of as the minimal
+resources required for a virtual task. The default slot size is 1 core.
+
+.. include:: common/job-param-batch.rst
+
+.. include:: common/job-param-additional.rst
+
+CONSTRAINTS
+===========
+
+.. include:: common/job-constraints.rst
+
+DEPENDENCIES
+============
+
+.. include:: common/job-dependencies.rst
+
+ENVIRONMENT
+===========
+
+By default, :man1:`flux-alloc` duplicates the current environment when
+submitting jobs. However, a set of environment manipulation options are
+provided to give fine control over the requested environment submitted
+with the job.
+
+.. note::
+ The actual environment of the initial program is subject to the caveats
+ described in the :ref:`initial_program_environment` section of
+ :man7:`flux-environment`.
+
+.. include:: common/job-environment.rst
+
+ENV RULES
+---------
+
+.. include:: common/job-env-rules.rst
+
+PROCESS RESOURCE LIMITS
+=======================
+
+By default these commands propagate some common resource limits (as described
+in :linux:man2:`getrlimit`) to the job by setting the ``rlimit`` job shell
+option in jobspec. The set of resource limits propagated can be controlled
+via the :option:`--rlimit=RULE` option:
+
+.. include:: common/job-process-resource-limits.rst
+
+EXIT STATUS
+===========
+
+The job exit status is normally the batch script exit status.
+This result is stored in the KVS.
+
+OTHER OPTIONS
+=============
+
+.. include:: common/job-other-options.rst
+
+.. include:: common/job-other-batch.rst
+
+SHELL OPTIONS
+=============
+
+Some options that affect the parallel runtime environment of the Flux instance
+started by :program:`flux alloc` are provided by the Flux shell.
+These options are described in detail in the
+:ref:`SHELL OPTIONS ` section of :man1:`flux-shell`.
+A list of the most commonly needed options follows.
+
+Usage: :option:`flux alloc -o NAME[=ARG]`.
+
+.. make :option: references in the included table x-ref to flux-shell(1)
+.. program:: flux shell
+.. include:: common/job-shell-options.rst
+.. program:: flux alloc
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+SEE ALSO
+========
+
+:man1:`flux-run`, :man1:`flux-submit`, :man1:`flux-batch`,
+:man1:`flux-bulksubmit`, :man7:`flux-environment`
diff --git a/doc/man1/flux-archive.rst b/doc/man1/flux-archive.rst
new file mode 100644
index 000000000000..35f8422ac6f5
--- /dev/null
+++ b/doc/man1/flux-archive.rst
@@ -0,0 +1,317 @@
+===============
+flux-archive(1)
+===============
+
+
+SYNOPSIS
+========
+
+| **flux** **archive** **create** [*-n NAME*] [*-C DIR*] *PATH* ...
+| **flux** **archive** **list** [*-n NAME*] [*--long*] [*PATTERN*]
+| **flux** **archive** **extract** [*-n NAME*] [*-C DIR*] [*PATTERN*]
+| **flux** **archive** **remove** [*-n NAME*] [*-f*]
+
+
+DESCRIPTION
+===========
+
+.. program:: flux archive
+
+:program:`flux archive` stores multiple files in an RFC 37 archive
+under a single KVS key. The archive can be efficiently extracted in
+parallel across the Flux instance, leveraging the scalability properties
+of the KVS and its content addressable data store.
+
+Sparse files such as file system images for virtual machines are archived
+efficiently.
+
+File discretionary access permissions are preserved, but file attributes,
+ACLs, and group ownership are not.
+
+The ``stage-in`` shell plugin described in :man1:`flux-shell` may be used to
+extract previously archived files into the directory referred to by
+:envvar:`FLUX_JOB_TMPDIR` or another directory.
+
+Due to the potential impact on Flux's storage footprint on rank 0, this
+command is limited to instance owners, e.g. it works in batch jobs and
+allocations but not at the system level.
+
+
+COMMANDS
+========
+
+create
+------
+
+.. program:: flux archive create
+
+:program:`flux archive create` archives one or more file *PATH* arguments.
+If a *PATH* refers to a directory, the directory is recursively archived.
+If a file is encountered that is not readable, or has a type other than
+regular file, directory, or symbolic link, a fatal error occurs.
+
+.. option:: -n, --name=NAME
+
+ Specify the archive name. If a name is not specified, ``main`` is used.
+
+ The archive will be committed to the KVS as ``archive.NAME``.
+
+.. option:: --overwrite
+
+ Unlink ``archive.NAME`` and ``archive.NAME_blobs`` from the KVS, and
+ unmap all files associated with *NAME* that were previously archived
+ with :option:`--mmap` before creating the archive.
+
+ Without :option:`--overwrite` or :option:`--append`, it is a fatal error
+ if *NAME* exists.
+
+.. option:: --append
+
+ If *NAME* exists, append new content to the existing archive.
+ Otherwise create it from scratch.
+
+ Due to the way the KVS handles key changes, appending :math:`M` bytes to
+ to a key of size :math:`N` consumes roughly :math:`2N + M` bytes in the
+ backing store, while separate keys consume :math:`N + M`. As a consequence,
+ creating multiple archives may be cheaper than building one iteratively
+ with :option:`--append`.
+
+.. option:: -C, --directory=DIR
+
+ Change to the specified directory before performing the operation.
+
+.. option:: --no-force-primary
+
+ Create the archive in the default KVS namespace, honoring
+ :envvar:`FLUX_KVS_NAMESPACE`, if set. By default, the primary KVS
+ namespace is used.
+
+.. option:: --preserve
+
+ Write additional KVS metadata so that the archive remains intact across
+ a Flux restart with garbage collection.
+
+ The metadata will be committed to the KVS as ``archive.NAME_blobs``.
+
+.. option:: -v, --verbose=[LEVEL]
+
+ List files on standard error as the archive is created.
+
+.. option:: --chunksize=N
+
+ Limit the content blob size to N bytes. Set to 0 for unlimited.
+ N may be specified as a floating point number with multiplicative suffix
+ k,K=1024, M=1024\*1024, or G=1024\*1024\*1024 up to ``INT_MAX``.
+ The default is 1M.
+
+.. option:: --small-file-threshold=N
+
+ Set the threshold in bytes for a small file. A small file is represented
+ directly in the archive, as opposed to the content store. Set to 0 to
+ always use the content store. N may be specified as a floating point
+ number with multiplicative suffix k,K=1024, M=1024\*1024, or
+ G=1024\*1024\*1024 up to ``INT_MAX``. The default is 1K.
+
+.. option:: --mmap
+
+ For large files, use :linux:man2:`mmap` to map file data into the content
+ store rather than copying it. This only works on rank 0, and does not work
+ with :option:`--preserve` or :option:`--no-force-primary`. Furthermore,
+ the files must remain available and unchanged while the archive exists.
+ This is most appropriate for truly large files such as VM images.
+
+ .. warning::
+
+ The rank 0 Flux broker may die with a SIGBUS error if a mapped file is
+ removed or truncated, and subsequently accessed, since that renders
+ pages mapped into the brokers address space invalid.
+
+ If mapped file content changes, access may fail if the original data
+ is not cached, but under no circumstances will the new content be
+ returned.
+
+list
+----
+
+.. program:: flux archive list
+
+:program:`flux archive list` shows the archive contents on standard output.
+If *PATTERN* is specified, only the files that match the :linux:man7:`glob`
+pattern are listed.
+
+.. option:: -l, --long
+
+ List the archive in long form, including file type, mode, and size.
+
+.. option:: --raw
+
+ List the RFC 37 file objects in JSON form, without decoding.
+
+.. option:: -n, --name=NAME
+
+ Specify the archive name. If a name is not specified, ``main`` is used.
+
+.. option:: --no-force-primary
+
+ List the archive in the default KVS namespace, honoring
+ :envvar:`FLUX_KVS_NAMESPACE`, if set. By default, the primary KVS
+ namespace is used.
+
+remove
+------
+
+.. program:: flux archive remove
+
+:program:`flux archive remove` expunges an archive. The archive's KVS keys
+are unlinked, and any files previously mapped with :option:`--mmap` are
+unmapped.
+
+.. option:: -n, --name=NAME
+
+ Specify the archive name. If a name is not specified, ``main`` is used.
+
+.. option:: --no-force-primary
+
+ Remove the archive in the default KVS namespace, honoring
+ :envvar:`FLUX_KVS_NAMESPACE`, if set. By default, the primary KVS
+ namespace is used.
+
+.. option:: -f, --force
+
+ Don't fail if the archive does not exist.
+
+
+extract
+-------
+
+.. program:: flux archive extract
+
+:program:`flux archive extract` extracts files from a KVS archive.
+If *PATTERN* is specified, only the files that match the :linux:man7:`glob`
+pattern are extracted.
+
+.. option:: -t, --list-only
+
+ List files in the archive without extracting.
+
+.. option:: -n, --name=NAME
+
+ Specify the archive name. If a name is not specified, ``main`` is used.
+
+.. option:: -C, --directory=DIR
+
+ Change to the specified directory before performing the operation.
+
+ When extracting files in parallel, take care when specifying *DIR*:
+
+ - It should have enough space to hold the extracted files.
+
+ - It should not be a fragile network file system such that parallel
+ writes could cause a distributed denial of service.
+
+ - It should not already be shared among the nodes of your job.
+
+.. option:: -v, --verbose=[LEVEL]
+
+ List files on standard error as the archive is extracted.
+
+.. option:: --overwrite
+
+ Overwrite existing files when extracting. :program:`flux archive extract`
+ normally refuses to do this and treats it as a fatal error.
+
+.. option:: --waitcreate[=FSD]
+
+ Wait for the archive key to appear in the KVS if it doesn't exist.
+ This may be necessary in some circumstances as noted in `CAVEATS`_
+ below.
+
+ If *FSD* is specified, it is interpreted as a timeout value in RFC 23
+ Flux Standard Duration format.
+
+.. option:: --no-force-primary
+
+ Extract from the archive in the default KVS namespace, honoring
+ :envvar:`FLUX_KVS_NAMESPACE`, if set. By default, the primary KVS
+ namespace is used.
+
+CAVEATS
+=======
+
+The KVS employs an "eventually consistent" cache update model, which
+means one has to be careful when writing a key on one broker rank and
+reading it on other broker ranks. Without some form of synchronization,
+there is a short period of time where the KVS cache on the other ranks
+may not yet have the new data.
+
+This is not an issue for Example 2 below, where a batch script creates
+an archive, then submits jobs that read the archive because job
+submission and execution already include KVS synchronization.
+In other situations such as Example 1, it is advisable to use
+:option:`--waitcreate` or to explicitly synchronize between writing
+the archive and reading it, e.g.
+
+.. code-block:: console
+
+ flux exec -r all flux kvs wait $(flux kvs version)
+
+
+EXAMPLES
+========
+
+Example 1: a batch script that archives data from ``/project/dataset1``, then
+replicates it in a temporary directory on each node of the batch allocation
+where it can be used by multiple jobs.
+
+.. code-block:: console
+
+ #!/bin/bash
+
+ flux archive create -C /project dataset1
+ flux exec -r all mkdir -p /tmp/project
+ flux exec -r all flux archive extract --waitcreate -C /tmp/project
+
+ # app1 and app2 have access to local copy of dataset1
+ flux run -N1024 app1 --input=/tmp/project/dataset1
+ flux run -N1024 app2 --input=/tmp/project/dataset1
+
+ # clean up
+ flux exec -r all rm -rf /tmp/project
+ flux archive remove
+
+Example 2: a batch script that archives a large executable and a data set,
+then uses the ``stage-in`` shell plugin to copy them to
+:envvar:`FLUX_JOB_TMPDIR` which is automatically cleaned up after each job.
+
+.. code-block:: console
+
+ #!/bin/bash
+
+ flux archive create --name=dataset1 -C /project dataset1
+ flux archive create --name=app --mmap -C /home/fred app
+
+ flux run -N1024 -o stage-in.names=app,dataset1 \
+ {{tmpdir}}/app --input={{tmpdir}}/dataset1
+
+ # clean up
+ flux archive remove --name=dataset1
+ flux archive remove --name=app
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+FLUX RFC
+========
+
+| :doc:`rfc:spec_16`
+| :doc:`rfc:spec_23`
+| :doc:`rfc:spec_37`
+
+
+SEE ALSO
+========
+
+:man1:`flux-shell`, :man1:`flux-kvs`, :man1:`flux-exec`
diff --git a/doc/man1/flux-batch.rst b/doc/man1/flux-batch.rst
new file mode 100644
index 000000000000..092314235358
--- /dev/null
+++ b/doc/man1/flux-batch.rst
@@ -0,0 +1,227 @@
+.. flux-help-include: true
+.. flux-help-section: submission
+
+=============
+flux-batch(1)
+=============
+
+
+SYNOPSIS
+========
+
+**flux** **batch** [OPTIONS] SCRIPT ...
+
+**flux** **batch** [OPTIONS] --wrap COMMAND ...
+
+
+DESCRIPTION
+===========
+
+.. program:: flux batch
+
+:program:`flux-batch` submits *SCRIPT* to run as the initial program of a Flux
+subinstance. *SCRIPT* refers to a file that is copied at the time of
+submission. Once resources are allocated, *SCRIPT* executes on the first
+node of the allocation, with any remaining free arguments supplied as *SCRIPT*
+arguments. Once *SCRIPT* exits, the Flux subinstance exits and resources are
+released to the enclosing Flux instance.
+
+If there are no free arguments, the script is read from standard input.
+
+If the :option:`--wrap` option is used, the script is created by wrapping the
+free arguments or standard input in a shell script prefixed with ``#!/bin/sh``.
+
+If the job request is accepted, its jobid is printed on standard output and the
+command returns. The job runs when the Flux scheduler fulfills its resource
+allocation request. :man1:`flux-jobs` may be used to display the job status.
+
+Flux commands that are run from the batch script refer to the subinstance.
+For example, :man1:`flux-run` would launch work there. A Flux command run
+from the script can be forced to refer to the enclosing instance by supplying
+the :option:`flux --parent` option.
+
+Flux commands outside of the batch script refer to their enclosing instance,
+often a system instance. :man1:`flux-proxy` establishes a connection to a
+running subinstance by jobid, then spawns a shell in which Flux commands refer
+to the subinstance. For example:
+
+::
+
+ $ flux uptime
+ 07:48:42 run 2.1d, owner flux, depth 0, size 8
+ $ flux batch -N 2 --queue=batch mybatch.sh
+ ÆM7Zq9AKHno
+ $ flux proxy ÆM7Zq9AKHno
+ $ flux uptime
+ 07:47:18 run 1.6m, owner user42, depth 1, size 2
+ $ flux top
+ ...
+ $ exit
+ $
+
+Other commands accept a jobid argument and establish the connection
+automatically. For example:
+
+::
+
+ $ flux batch -N 2 --queue=batch mybatch.sh
+ ÆM7Zq9AKHno
+ $ flux top ÆM7Zq9AKHno
+ ...
+ $
+
+Batch scripts may contain submission directives denoted by ``flux:``
+as described in RFC 36. See `SUBMISSION DIRECTIVES`_ below.
+
+The available OPTIONS are detailed below.
+
+JOB PARAMETERS
+==============
+
+:man1:`flux-batch` and :man1:`flux-alloc` do not launch tasks directly, and
+therefore job parameters are specified in terms of resource slot size
+and number of slots. A resource slot can be thought of as the minimal
+resources required for a virtual task. The default slot size is 1 core.
+
+.. include:: common/job-param-batch.rst
+
+.. include:: common/job-param-additional.rst
+
+STANDARD I/O
+============
+
+For :man1:`flux-batch` the default :option:`--output` *TEMPLATE*
+is *flux-{{id}}.out*. To force output to KVS so it is available with
+``flux job attach`` or :man1:`flux-watch` , set the :option:`--output`
+*TEMPLATE* to *none* or *kvs*.
+
+.. include:: common/job-standard-io.rst
+
+CONSTRAINTS
+===========
+
+.. include:: common/job-constraints.rst
+
+DEPENDENCIES
+============
+
+.. include:: common/job-dependencies.rst
+
+ENVIRONMENT
+===========
+
+By default, :man1:`flux-batch` duplicates the current environment when
+submitting jobs. However, a set of environment manipulation options
+are provided to give fine control over the requested environment
+submitted with the job.
+
+.. note::
+ The actual environment of the initial program is subject to the caveats
+ described in the :ref:`initial_program_environment` section of
+ :man7:`flux-environment`.
+
+.. include:: common/job-environment.rst
+
+ENV RULES
+---------
+
+.. include:: common/job-env-rules.rst
+
+PROCESS RESOURCE LIMITS
+=======================
+
+By default these commands propagate some common resource limits (as described
+in :linux:man2:`getrlimit`) to the job by setting the ``rlimit`` job shell
+option in jobspec. The set of resource limits propagated can be controlled
+via the :option:`--rlimit=RULE` option:
+
+.. include:: common/job-process-resource-limits.rst
+
+EXIT STATUS
+===========
+
+The job exit status is normally the batch script exit status.
+This result is stored in the KVS.
+
+OTHER OPTIONS
+=============
+
+.. include:: common/job-other-options.rst
+
+.. include:: common/job-other-batch.rst
+
+SHELL OPTIONS
+=============
+
+Some options that affect the parallel runtime environment of the Flux instance
+started by :program:`flux batch` are provided by the Flux shell.
+These options are described in detail in the
+:ref:`SHELL OPTIONS ` section of :man1:`flux-shell`.
+A list of the most commonly needed options follows.
+
+Usage: :option:`flux batch -o NAME[=ARG]`.
+
+.. make :option: references in the included table x-ref to flux-shell(1)
+.. program:: flux shell
+.. include:: common/job-shell-options.rst
+.. program:: flux batch
+
+SUBMISSION DIRECTIVES
+=====================
+
+The :program:`flux batch` command supports submission directives
+mixed within the submission script. The submission directive specification
+is fully detailed in RFC 36, but is summarized here for convenience:
+
+ * A submission directive is indicated by a line that starts with
+ a prefix of non-alphanumeric characters followed by a tag ``FLUX:`` or
+ ``flux:``. The prefix plus tag is called the *directive sentinel*. E.g.,
+ in the example below the sentinel is ``# flux:``: ::
+
+ #!/bin/sh
+ # flux: -N4 -n16
+ flux run -n16 hostname
+
+ * All directives in a file must use the same sentinel pattern, otherwise
+ an error will be raised.
+ * Directives must be grouped together - it is an error to include a
+ directive after any non-blank line that doesn't start with the common
+ prefix.
+ * The directive starts after the sentinel to the end of the line.
+ * The ``#`` character is supported as a comment character in directives.
+ * UNIX shell quoting is supported in directives.
+ * Triple quoted strings can be used to include newlines and quotes without
+ further escaping. If a triple quoted string is used across multiple lines,
+ then the opening and closing triple quotes must appear at the end of the
+ line. For example ::
+
+ # flux: --setattr=user.conf="""
+ # flux: [config]
+ # flux: item = "foo"
+ # flux: """
+
+Submission directives may be used to set default command line options for
+:program:`flux batch` for a given script. Options given on the command line
+override those in the submission script, e.g.: ::
+
+ $ flux batch --job-name=test-name --wrap <<-EOF
+ > #flux: -N4
+ > #flux: --job-name=name
+ > flux run -N4 hostname
+ > EOF
+ Æ112345
+ $ flux jobs -no {name} Æ112345
+ test-name
+
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+SEE ALSO
+========
+
+:man1:`flux-submit`, :man1:`flux-run`, :man1:`flux-alloc`,
+:man1:`flux-bulksubmit` :man7:`flux-environment`
diff --git a/doc/man1/flux-broker.adoc b/doc/man1/flux-broker.adoc
deleted file mode 100644
index 8dca5f3d153f..000000000000
--- a/doc/man1/flux-broker.adoc
+++ /dev/null
@@ -1,94 +0,0 @@
-// flux-help-description: Invoke Flux comms message broker daemon
-FLUX-BROKER(1)
-==============
-:doctype: manpage
-
-
-NAME
-----
-flux-broker - Flux comms message broker daemon
-
-
-SYNOPSIS
---------
-*flux-broker* ['OPTIONS'] ['initial-program' ['args...']]
-
-
-DESCRIPTION
------------
-flux-broker(1) is a distributed message broker daemon that provides
-communications services within a Flux comms session. It may be
-launched as a parallel program under Flux or other resource managers
-that support PMI.
-
-Resource manager services are implemented as dynamically loadable
-plugins to flux-broker(1), termed "comms modules".
-
-flux-broker(1) instances within a comms session are interconnected using
-ZeroMQ sockets, and each is assigned a rank from 0 to size - 1.
-The rank 0 node is the root of a tree-based overlay network.
-In addition, there is a multicast pub/sub network for events, and
-a ring network for debugging. These networks may be accessed by
-Flux commands and comms modules using Flux API services.
-
-A periodic heartbeat event generated by rank 0 is used to synchronize
-resource manager activities across the session.
-
-A logging service aggregates Flux log messages across the session and
-emits them to a configured destination on rank 0.
-
-After its overlay networks have completed wire-up, flux-broker(1)
-starts the initial program on rank 0. If none is specified on
-the broker command line, an interactive shell is launched.
-
-
-OPTIONS
--------
-*-h, --help*::
-Summarize available options.
-
-*-v, --verbose*::
-Be annoyingly chatty.
-
-*-S, --setattr*='ATTR=VAL'::
-Set initial value for broker attribute.
-
-*-k, --k-ary*='N'::
-Set the branching factor of this comms session's tree based overlay
-network (default: 2).
-
-*-H, --heartrate*='N.N'::
-Set the session heartrate in seconds. The valid range is 0.01 to 30.0
-(default: 2.0).
-
-*-X, --module-path*='PATH'::
-Override the compiled-in module search path (colon-separated).
-The default is to search install paths.
-
-*-s, --security*='MODE'::
-Set the security mode. The mode may be 'none', 'plain', or 'curve'
-(default: curve). See flux-keygen(1) for more information.
-
-*-g, --shutdown-grace*='SECS'::
-Specify the shutdown grace period, in seconds (default: guess based
-on session size).
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-flux-broker-attributes(7)
diff --git a/doc/man1/flux-broker.rst b/doc/man1/flux-broker.rst
new file mode 100644
index 000000000000..b3d435f7b630
--- /dev/null
+++ b/doc/man1/flux-broker.rst
@@ -0,0 +1,70 @@
+==============
+flux-broker(1)
+==============
+
+
+SYNOPSIS
+========
+
+**flux-broker** [*OPTIONS*] [*initial-program* [*args...*]]
+
+DESCRIPTION
+===========
+
+.. program:: flux broker
+
+:program:`flux broker` is a distributed message broker daemon that provides
+communications services within a Flux instance. It may be
+launched as a parallel program under Flux or other resource managers
+that support PMI.
+
+Resource manager services are implemented as dynamically loadable
+modules.
+
+Brokers within a Flux instance are interconnected using
+ZeroMQ sockets, and each is assigned a rank from 0 to size - 1.
+The rank 0 node is the root of a tree-based overlay network.
+This network may be accessed by Flux commands and modules
+using Flux API services.
+
+A logging service aggregates Flux log messages across the instance and
+emits them to a configured destination on rank 0.
+
+After its overlay network has completed wire-up, :program:`flux broker`
+starts the initial program on rank 0. If none is specified on
+the broker command line, an interactive shell is launched.
+
+
+OPTIONS
+=======
+
+.. option:: -h, --help
+
+ Summarize available options.
+
+.. option:: -v, --verbose
+
+ Be annoyingly chatty.
+
+.. option:: -S, --setattr=ATTR=VAL
+
+ Set initial value for broker attribute.
+
+.. option:: -c, --config-path=PATH
+
+ Set the PATH to broker configuration. If PATH is a directory, then
+ read all TOML files from that directory. If PATH is a file, then load
+ configuration as JSON if the file extension is ``.json``, otherwise
+ load the file as TOML.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man7:`flux-broker-attributes`
diff --git a/doc/man1/flux-bulksubmit.rst b/doc/man1/flux-bulksubmit.rst
new file mode 100644
index 000000000000..f530ee1a256b
--- /dev/null
+++ b/doc/man1/flux-bulksubmit.rst
@@ -0,0 +1,252 @@
+.. flux-help-include: true
+.. flux-help-section: submission
+
+==================
+flux-bulksubmit(1)
+==================
+
+
+SYNOPSIS
+========
+
+**flux** **bulksubmit** [OPTIONS] COMMAND...
+
+
+DESCRIPTION
+===========
+
+.. program:: flux bulksubmit
+
+:program:`flux bulksubmit` allows rapid bulk submission of jobs using
+an interface similar to GNU parallel or ``xargs``. The command takes
+inputs on stdin or the command line (separated by ``:::``), and submits
+the supplied command template and options as one job per input combination.
+
+The replacement is done using Python's ``string.format()``, which is
+supplied a list of inputs on each iteration. Therefore, in the common case
+of a single input list, ``{}`` will work as the substitution string, e.g.::
+
+ $ seq 1 4 | flux bulksubmit echo {}
+ bulksubmit: submit echo 1
+ bulksubmit: submit echo 2
+ bulksubmit: submit echo 3
+ bulksubmit: submit echo 4
+
+With :option:`--dry-run` :program:`flux bulksubmit` will print the args and
+command which would have been submitted, but will not perform any job
+submission.
+
+The :program:`flux bulksubmit` command can also take input lists on the command
+line. The inputs are separated from each other and the command with the
+special delimiter ``:::``::
+
+ $ flux bulksubmit echo {} ::: 1 2 3 4
+ bulksubmit: submit echo 1
+ bulksubmit: submit echo 2
+ bulksubmit: submit echo 3
+ bulksubmit: submit echo 4
+
+Multiple inputs are combined, in which case each input is passed as a
+positional parameter to the underlying ``format()``, so should be accessed
+by index::
+
+ $ flux bulksubmit --dry-run echo {1} {0} ::: 1 2 ::: 3 4
+ bulksubmit: submit echo 3 1
+ bulksubmit: submit echo 4 1
+ bulksubmit: submit echo 3 2
+ bulksubmit: submit echo 4 2
+
+If the generation of all combinations of an input list with other inputs is not
+desired, the special input delimited ``:::+`` may be used to "link" the input,
+so that only one argument from this source will be used per other input,
+e.g.::
+
+ $ flux bulksubmit --dry-run echo {0} {1} ::: 1 2 :::+ 3 4
+ bulksubmit: submit 1 3
+ bulksubmit: submit 2 4
+
+The linked input will be cycled through if it is shorter than other inputs.
+
+An input list can be read from a file with ``::::``::
+
+ $ seq 0 3 >inputs
+ $ flux bulksubmit --dry-run :::: inputs
+ bulksubmit: submit 0
+ bulksubmit: submit 1
+ bulksubmit: submit 2
+ bulksubmit: submit 3
+
+If the filename is ``-`` then ``stdin`` will be used. This is useful
+for including ``stdin`` when reading other inputs.
+
+The delimiter ``::::+`` indicates that the next file is to be linked to
+the inputs instead of combined with them, as with ``:::+``.
+
+There are several predefined attributes for input substitution.
+These include:
+
+ - ``{.%}`` returns the input string with any extension removed.
+ - ``{./}`` returns the basename of the input string.
+ - ``{./%}`` returns the basename of the input string with any
+ extension removed.
+ - ``{.//}`` returns the dirname of the input string
+ - ``{seq}`` returns the input sequence number (0 origin)
+ - ``{seq1}`` returns the input sequence number (1 origin)
+ - ``{cc}`` returns the current ``id`` from use of :option:`--cc` or
+ :option:`--bcc`. Note that replacement of ``{cc}`` is done in a second
+ pass, since the :option:`--cc` option argument may itself be replaced in
+ the first substitution pass. If :option:`--cc`/:option:`--bcc` were not
+ used, then ``{cc}`` is replaced with an empty string. This is the only
+ substitution supported with :man1:`flux-submit`.
+
+Note that besides ``{seq}``, ``{seq1}``, and ``{cc}`` these attributes
+can also take the input index, e.g. ``{0.%}`` or ``{1.//}``, when multiple
+inputs are used.
+
+Additional attributes may be defined with the :option:`--define` option, e.g.::
+
+ $ flux bulksubmit --dry-run --define=p2='2**int(x)' -n {.p2} hostname \
+ ::: $(seq 0 4)
+ bulksubmit: submit -n1 hostname
+ bulksubmit: submit -n2 hostname
+ bulksubmit: submit -n4 hostname
+ bulksubmit: submit -n8 hostname
+ bulksubmit: submit -n16 hostname
+
+The input string being indexed is passed to defined attributes via the
+local ``x`` as seen above.
+
+The available OPTIONS are detailed below.
+
+JOB PARAMETERS
+==============
+
+These commands accept only the simplest parameters for expressing
+the size of the parallel program and the geometry of its task slots:
+
+Common resource options
+-----------------------
+
+These commands take the following common resource allocation options:
+
+.. include:: common/job-param-common.rst
+
+Per-task options
+----------------
+
+:man1:`flux-run`, :man1:`flux-submit` and :man1:`flux-bulksubmit` take two
+sets of mutually exclusive options to specify the size of the job request.
+The most common form uses the total number of tasks to run along with
+the amount of resources required per task to specify the resources for
+the entire job:
+
+.. include:: common/job-param-pertask.rst
+
+Per-resource options
+--------------------
+
+The second set of options allows an amount of resources to be specified
+with the number of tasks per core or node set on the command line. It is
+an error to specify any of these options when using any per-task option
+listed above:
+
+.. include:: common/job-param-perres.rst
+
+Additional job options
+----------------------
+
+These commands also take following job parameters:
+
+.. include:: common/job-param-additional.rst
+
+STANDARD I/O
+============
+
+By default, task stdout and stderr streams are redirected to the
+KVS, where they may be accessed with the ``flux job attach`` command.
+
+In addition, :man1:`flux-run` processes standard I/O in real time,
+emitting the job's I/O to its stdout and stderr.
+
+.. include:: common/job-standard-io.rst
+
+CONSTRAINTS
+===========
+
+.. include:: common/job-constraints.rst
+
+DEPENDENCIES
+============
+
+.. include:: common/job-dependencies.rst
+
+ENVIRONMENT
+===========
+
+By default, these commands duplicate the current environment when submitting
+jobs. However, a set of environment manipulation options are provided to
+give fine control over the requested environment submitted with the job.
+
+.. include:: common/job-environment.rst
+
+ENV RULES
+---------
+
+.. include:: common/job-env-rules.rst
+
+PROCESS RESOURCE LIMITS
+=======================
+
+By default these commands propagate some common resource limits (as described
+in :linux:man2:`getrlimit`) to the job by setting the ``rlimit`` job shell
+option in jobspec. The set of resource limits propagated can be controlled
+via the :option:`--rlimit=RULE` option:
+
+.. include:: common/job-process-resource-limits.rst
+
+EXIT STATUS
+===========
+
+The job exit status, normally the largest task exit status, is stored
+in the KVS. If one or more tasks are terminated with a signal,
+the job exit status is 128+signo.
+
+The ``flux-job attach`` command exits with the job exit status.
+
+In addition, :man1:`flux-run` runs until the job completes and exits
+with the job exit status.
+
+OTHER OPTIONS
+=============
+
+.. include:: common/job-other-options.rst
+
+.. include:: common/job-other-run.rst
+
+SHELL OPTIONS
+=============
+
+Some options that affect the parallel runtime environment are provided by the
+Flux shell. These options are described in detail in the
+:ref:`SHELL OPTIONS ` section of :man1:`flux-shell`.
+A list of the most commonly needed options follows.
+
+Usage: :option:`flux bulksubmit -o NAME[=ARG]`.
+
+.. make :option: references in the included table x-ref to flux-shell(1)
+.. program:: flux shell
+.. include:: common/job-shell-options.rst
+.. program:: flux bulksubmit
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-run`, :man1:`flux-submit`, :man1:`flux-alloc`,
+:man1:`flux-batch`, :man7:`flux-environment`
+
diff --git a/doc/man1/flux-cancel.rst b/doc/man1/flux-cancel.rst
new file mode 100644
index 000000000000..8cf8dba402f7
--- /dev/null
+++ b/doc/man1/flux-cancel.rst
@@ -0,0 +1,63 @@
+.. flux-help-description: cancel one or more jobs
+.. flux-help-section: jobs
+
+==============
+flux-cancel(1)
+==============
+
+
+SYNOPSIS
+========
+
+**flux** **cancel** [*OPTIONS*] [*JOBID...*]
+
+DESCRIPTION
+===========
+
+.. program:: flux cancel
+
+:program:`flux cancel` cancels one or more jobs by raising a job exception of
+type=cancel. An optional message included with the cancel exception may be
+provided via the :option:`--message` option. Canceled jobs are immediately
+sent SIGTERM followed by SIGKILL after a configurable timeout (default=5s).
+
+:program:`flux cancel` can target multiple jobids by either taking them on the
+command line, or via the selection options :option:`--all`, :option:`--user`,
+or :option:`--states`. It is an error to provide jobids on the command line
+and use one or more of the selection options.
+
+By default :option:`--all` will target all jobs for the current user. To
+target all jobs for all users, use :option:`--user=all` (only the instance
+owner is allowed to use :option:`--user=all`). To see how many jobs
+:program:`flux cancel` would kill, use the :option:`--dry-run` option.
+
+OPTIONS
+=======
+
+.. option:: -n, --dry-run
+
+ Do not cancel any jobs, but print a message indicating how many jobs
+ would have been canceled.
+
+.. option:: -m, --message=NOTE
+
+ Set an optional exception note.
+
+.. option:: -u, --user=USER
+
+ Set target user. The instance owner may specify *all* for all users.
+
+.. option:: -S, --states=STATES
+
+ Set target job states (default: active). Valid states include
+ depend, priority, sched, run, pending, running, active.
+
+.. option:: -q, --quiet
+
+ Suppress output if no jobs match
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
diff --git a/doc/man1/flux-config.rst b/doc/man1/flux-config.rst
new file mode 100644
index 000000000000..4c5ec92f9f72
--- /dev/null
+++ b/doc/man1/flux-config.rst
@@ -0,0 +1,215 @@
+.. flux-help-description: Manage/query Flux configuration
+
+==============
+flux-config(1)
+==============
+
+
+SYNOPSIS
+========
+
+| **flux** **config** **get** [*--default=VALUE*] [*--type=TYPE*] [*NAME*]
+| **flux** **config** **builtin** [*NAME*]
+| **flux** **config** **load** [*PATH*]
+| **flux** **config** **reload**
+
+
+DESCRIPTION
+===========
+
+The :program:`flux config` manipulates the configuration of the local broker.
+
+COMMANDS
+========
+
+get
+---
+
+.. program:: flux config get
+
+:program:`flux config get` queries the TOML configuration for a given Flux
+broker. if *NAME* is unspecified, it dumps the entire configuration object.
+Otherwise, *NAME* is expected to be a period-delimited path name representing
+a TOML key. Return values are printed in string-encoded JSON form, except for
+string values, which are printed without quotes to simplify their use in shell
+scripts.
+
+.. option:: -d, --default=VALUE
+
+ Substitute *VALUE* if *NAME* is not set in the configuration, and exit
+ with a return code of zero.
+
+.. option:: -q, --quiet
+
+ Suppress printing of errors if *NAME* is not set and :option:`--default` was
+ not specified. This may be convenient to avoid needing to redirect standard
+ error in a shell script.
+
+.. option:: -t, --type=TYPE
+
+ Require that the value has the specified type, or exit with a nonzero exit
+ code. Valid types are *string*, *integer*, *real*, *boolean*, *object*, and
+ *array*. In addition, types of *fsd*, *fsd-integer*, and *fsd-real* ensure
+ that a value is a both a string and valid Flux Standard Duration.
+ *fsd* prints the value in its human-readable, string form. *fsd-integer*
+ and *fsd-real* print the value in integer and real seconds, respectively.
+
+.. option:: -c, --config-path=PATH
+
+ Read configuration from PATH instead of fetching configuration from local
+ broker. If PATH is a directory, then read all TOML files from that
+ directory. If PATH is a file, then load configuration as JSON if the file
+ extension is ``.json``, otherwise load the file as TOML. As a special case,
+ ``system``, ``security``, and ``imp`` may be used as shorthand for the
+ compiled-in paths to system configuration objects.
+
+
+builtin
+-------
+
+.. program:: flux config builtin
+
+:program:`flux config builtin` prints compiled-in Flux configuration values.
+See `BUILTIN VALUES`_ below for a list of builtin
+configuration key names. This command is available to all users.
+
+.. note::
+ :program:`flux config get` and :program:`flux config builtin` refer to
+ disjoint key namespaces. Flux behavior is determined by a combination of
+ these values, :man7:`flux-broker-attributes`, and other factors. This
+ disjoint configuration scheme is subject to change in future releases of
+ Flux.
+
+.. note::
+ :program:`flux config builtin` uses a heuristic to determine if :man1:`flux`
+ was run from the flux-core source tree, and substitutes source tree
+ specific values if found to be in tree. This enables Flux testing without
+ requiring installation.
+
+.. option:: --intree
+ Force :program:`flux config builtin` to return in-tree paths.
+
+.. option:: --installed
+ Force :program:`flux config builtin` to return installed paths.
+
+load
+----
+
+.. program:: flux config load
+
+:program:`flux config load` replaces the current config with an object read
+from standard input (JSON or TOML), or from ``*.toml`` in *PATH*, if specified.
+
+reload
+------
+
+.. program:: flux config reload
+
+:program:`flux config reload` tells :man1:`flux-broker` to reload its TOML
+configuration after it has been modified.
+
+On Flux instances started with :linux:man1:`systemd`,
+:program:`systemctl reload flux` invokes this command.
+This command is restricted to the instance owner.
+
+This command does not have an immediate effect in all cases. For more
+information, refer to the :ref:`flux_config_caveats` section of
+:man5:`flux-config`.
+
+
+BUILTIN VALUES
+==============
+
+The following configuration keys may be printed with
+:program:`flux config builtin`:
+
+**rc1_path**
+ The rc1 script path used by :man1:`flux-broker`, unless overridden by
+ the ``broker.rc1_path`` broker attribute.
+
+**rc3_path**
+ The rc3 script path used by :man1:`flux-broker`, unless overridden by
+ the ``broker.rc1_path`` broker attribute.
+
+**shell_path**
+ The path to the :man1:`flux-shell` executable used by the exec service.
+
+**shell_pluginpath**
+ The search path used by :man1:`flux-shell` to locate plugins, unless
+ overridden by setting the ``conf.shell_pluginpath`` broker attribute.
+
+**shell_initrc**
+ The initrc script path used by :man1:`flux-shell`, unless overridden by
+ setting the ``conf.shell_initrc`` broker attribute.
+
+**jobtap_pluginpath**
+ The search path used by the job manager to locate
+ :man7:`flux-jobtap-plugins`.
+
+**rundir**
+ The configured ``${runstatedir}/flux`` directory.
+
+**lua_cpath_add**
+ Consulted by :man1:`flux` when setting the :envvar:`LUA_CPATH` environment
+ variable.
+
+**lua_path_add**
+ Consulted by :man1:`flux` when setting the :envvar:`LUA_PATH` environment
+ variable.
+
+**python_path**
+ Consulted by :man1:`flux` when setting the :envvar:`PYTHONPATH` environment
+ variable.
+
+**man_path**
+ Consulted by :man1:`flux` when setting the :envvar:`MANPATH` environment
+ variable.
+
+**exec_path**
+ Consulted by :man1:`flux` when setting the :envvar:`FLUX_EXEC_PATH`
+ environment variable.
+
+**connector_path**
+ Consulted by :man1:`flux` when setting the :envvar:`FLUX_CONNECTOR_PATH`
+ environment variable.
+
+**module_path**
+ Consulted by :man1:`flux` when setting the :envvar:`FLUX_MODULE_PATH`
+ environment variable.
+
+**pmi_library_path**
+ Consulted by the :man1:`flux-shell` pmi plugin when setting the
+ :envvar:`FLUX_PMI_LIBRARY_PATH` environment variable.
+
+**cmdhelp_pattern**
+ Used by :man1:`flux` to generate a list of common commands when run without
+ arguments.
+
+**no_docs_path**
+
+
+EXAMPLES
+========
+
+::
+
+ $ flux config get --type=fsd-integer tbon.tcp_user_timeout
+ 60
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_23`
+
+
+SEE ALSO
+========
+
+:man5:`flux-config`
diff --git a/doc/man1/flux-content.adoc b/doc/man1/flux-content.adoc
deleted file mode 100644
index 653b3ab3dca8..000000000000
--- a/doc/man1/flux-content.adoc
+++ /dev/null
@@ -1,158 +0,0 @@
-// flux-help-command: content
-// flux-help-description: Access instance content storage
-FLUX-CONTENT(1)
-===============
-:doctype: manpage
-
-
-NAME
-----
-flux-content - access content service
-
-
-SYNOPSIS
---------
-*flux* *content* *load* ['--bypass-cache'] 'blobref'
-
-*flux* *content* *store* ['--bypass-cache']
-
-*flux* *content* *flush*
-
-*flux* *content* *dropcache*
-
-
-DESCRIPTION
------------
-Each Flux instance implements an append-only, content addressable
-storage service, which stores blobs of arbitrary content under
-message digest keys termed "blobrefs".
-
-*flux content store* accepts a blob on standard input, stores it,
-and prints the blobref on standard output.
-
-*flux content load* accepts a blobref argument, retrieves the
-corresponding blob, and writes it to standard output.
-
-After a store operation completes on any rank, the blob may be
-retrieved from any other rank.
-
-The content service includes a cache on each broker which improves
-scalability. The *flux content flush* command initiates store requests
-for any dirty entries in the local cache and waits for them to complete.
-This is mainly used in testing. The *flux content dropcache* command
-drops all non-essential entries in the local cache; that is, entries
-which can be removed without data loss.
-
-
-OPTIONS
--------
-*-b, --bypass-cache*::
-Bypass the in-memory cache, and directly access the backing store,
-if available (see below).
-
-BACKING STORE
--------------
-The rank 0 cache retains all content until a module providing
-the "content.backing" service is loaded which can offload content
-to some other place. The *content-sqlite* module provides this
-service, and is loaded by default.
-
-Content database files are stored persistently on rank 0 if the
-persist-directory broker attribute is set to a directory name for
-the session. Otherwise they are stored in the directory defined
-by the scratch-directory attribute and are cleaned up when the
-instance terminates.
-
-When one of these modules is loaded, it informs the rank 0
-cache of its availability, which triggers the cache to begin
-offloading entries. Once entries are offloaded, they are eligible
-for expiration from the rank 0 cache.
-
-To avoid data loss, once a content backing module is loaded,
-do not unload it unless the content cache on rank 0 has been flushed
-and the system is shutting down.
-
-
-CACHE EXPIRATION
-----------------
-The parameters affecting local cache expiration may be tuned with
-flux-setattr(1):
-
-*content.purge-target-entries*::
-The cache is purged to bring the number of cache entries less than
-or equal to this value
-(default 1048576).
-
-*content.purge-target-size*::
-The cache is purged to bring the sum of the size of cached blobs less
-than or equal to this value
-(default 16777216)
-
-*content.purge-old-entry*::
-Only entries that have not been accessed in *old-entry* heartbeat epochs
-are eligible for purge (default 5).
-
-*content.purge-large-entry*::
-Only entries with blob size greater than or equal to *large-entry* are
-purged to reach the size target (default 256).
-
-Expiration becomes active on every heartbeat, when the cache exceeds one
-or both of the targets configured above. Dirty or invalid entries are
-not eligible for purge.
-
-
-CACHE ACCOUNTING
-----------------
-Some accounting info for the local cache can be viewed with flux-getattr(1):
-
-*content.acct-entries*::
-The total number of cache entries.
-
-*content.acct-size*::
-The sum of the size of cached blobs.
-
-*content.acct-dirty*::
-The number of dirty cache entries.
-
-*content.acct-valid*::
-The number of valid cache entries.
-
-
-CACHE SEMANTICS
----------------
-The cache is write-through with respect to the rank 0 cache;
-that is, a store operation does not receive a response until it
-is valid in the rank 0 cache.
-
-The cache on rank 0 is write-back with respect to the backing store,
-if any; that is, a store operation may receive a response before
-it has been stored on the backing store.
-
-The cache is hierarchical. Rank 0 (the root of the tree based
-overlay network) holds all blobs stored in the instance.
-Other ranks keep only what a they heuristically determine to
-be of benefit. On ranks > 0, a load operation that cannot be fulfilled
-from the local cache is "faulted" in from the level above it.
-A store operation that reaches a level that has already cached the
-same content is "squashed"; that is, it receives a response without
-traveling further up the tree.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-https://github.com/flux-framework/rfc/blob/master/spec_10.adoc[RFC 10: Content Store]
diff --git a/doc/man1/flux-content.rst b/doc/man1/flux-content.rst
new file mode 100644
index 000000000000..758952c4d056
--- /dev/null
+++ b/doc/man1/flux-content.rst
@@ -0,0 +1,136 @@
+===============
+flux-content(1)
+===============
+
+
+SYNOPSIS
+========
+
+| **flux** **content** **load** [*--bypass-cache*] [*blobref* ...]
+| **flux** **content** **store** [*--bypass-cache*] [*--chunksize=N*]
+| **flux** **content** **flush**
+| **flux** **content** **dropcache**
+
+
+DESCRIPTION
+===========
+
+Each Flux instance implements an append-only, content addressable storage
+service. The content service stores blobs of arbitrary data under
+"blobref" keys. Blobrefs are derived from a hash of the data and thus can
+be computed in advance and always refer to the same blob.
+
+The leader broker (rank 0) holds the full data set, and normally offloads
+blobs to a sqlite database on disk. The database usually resides in the
+broker ``rundir`` which is created anew when Flux starts, and is cleaned
+up when Flux terminates. However if the ``statedir`` broker attribute is
+set, the database resides there and can persist across Flux restarts, but
+see `CAVEATS`_ below.
+
+The content service was designed for, and is primarily used by, the Flux KVS.
+Access is restricted to the instance owner.
+
+
+COMMANDS
+========
+
+store
+-----
+
+.. program:: flux content store
+
+:program:`flux content store` reads data from standard input to EOF, stores it
+(possibly splitting into multiple blobs), and prints blobref(s) on
+standard output, one per line.
+
+After a store operation completes on any rank, the blobs may be
+retrieved from any other rank.
+
+.. option:: -b, --bypass-cache
+
+ Bypass the in-memory cache, and directly access the backing store,
+ if available.
+
+.. option:: --chunksize=N
+
+ Split a blob into chunks of *N* bytes.
+
+load
+----
+
+.. program:: flux content load
+
+:program:`flux content load` reads blobrefs from standard input, one per line,
+or parses blobrefs on the command line (but not both). It then loads the
+corresponding blob(s), and concatenates them on standard output.
+
+.. option:: -b, --bypass-cache
+
+ Bypass the in-memory cache, and directly access the backing store,
+ if available.
+
+flush
+-----
+
+.. program:: flux content flush
+
+The content service includes a cache on each broker which improves
+scalability. The :program:`flux content flush` command initiates store requests
+for any dirty entries in the local cache and waits for them to complete.
+This is mainly used in testing.
+
+dropcache
+---------
+
+.. program:: flux content dropcache
+
+The :program:`flux content dropcache` command drops all non-essential entries
+in the local cache; that is, entries which can be removed without data loss.
+
+
+CAVEATS
+=======
+
+The KVS implements its hierarchical key space using a hash tree, where
+the hashes refer to content entries. As the KVS is used, the append-only
+nature of the content service results in an accumulation of unreferenced
+data. In restartable Flux instances, this is mitigated by
+:option:`flux shutdown --gc` offline garbage collection, where a dump of
+the current KVS root snapshot is created at shutdown, and the content
+database is removed and recreated from the dump at restart. This presents
+a problem for other users of the content service. If content needs to be
+preserved in this situation, the best recourse is to ensure it is linked
+into the KVS hash tree before the instance is shut down. The
+:option:`flux kvs put --treeobj` option is available for this purpose.
+
+A large or long-running Flux instance might generate a lot of content
+that is offloaded to ``rundir`` on the leader broker. If the file system
+(usually ``/tmp``) containing ``rundir`` is a ramdisk, this can lead to less
+memory available for applications on the leader broker, or to catastrophic
+failures if the file system fills up. Some workarounds for batch jobs are::
+
+ # exclude the leader (rank 0) broker from scheduling
+ flux batch --conf=resource.exclude=\"0\"
+
+ # redirect storage to a global file system (pre-create empty)
+ flux batch --broker-opts=--setattr=statedir=/path/to/directory
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_10`
+
+:doc:`rfc:spec_11`
+
+
+SEE ALSO
+========
+
+:man1:`flux-kvs`, :man7:`flux-broker-attributes`
diff --git a/doc/man1/flux-cron.adoc b/doc/man1/flux-cron.adoc
deleted file mode 100644
index 91c96c70b52f..000000000000
--- a/doc/man1/flux-cron.adoc
+++ /dev/null
@@ -1,286 +0,0 @@
-// flux-help-description: Schedule tasks on timers and events
-FLUX-CRON(1)
-===========
-:doctype: manpage
-
-NAME
-----
-flux-cron - Cron-like utility for Flux
-
-SYNOPSIS
---------
-*flux* *cron* 'COMMAND' ['OPTIONS']
-
-DESCRIPTION
------------
-The Flux cron service offers an interface for executing commands on
-triggers such as a time interval or Flux events. The service is
-implemented as a Flux extension module which, when loaded, manages
-a set of cron entries and uses the built-in 'cmb.exec' service to run
-a command associated with the entry each time the defined trigger is
-reached. As with 'flux-exec(1)', these tasks run as direct children
-of the flux-broker and run outside of the control of any loaded
-job scheduling service.
-
-The flux-cron(1) utility offers an interface to create, stop, start,
-query, and destroy these entries in the Flux cron service.
-
-For a detailed description of the cron service operation and how
-it executes tasks, see the OPERATION and TASK EXECUTION sections
-below.
-
-COMMANDS
---------
-*help* 'cmd'::
-Print help. If 'cmd' is provided, print help for that sub-command.
-
-*sync* [--epsilon='delay'] ['topic']::
-Query and modify the current *sync-event* behavior for the cron module.
-If a sync-event is set, the cron module will defer all task execution
-until an event matching the sync-event 'topic' is received. With '--epsilon'
-the cron module will *not* delay task execution if the task is normally
-scheduled to run within 'delay' of the matching event. Without any
-'topic' supplied on command line, 'flux cron sync' displays the current
-setting for sync. If a task is deferred due to sync-event, the
-'stats.deferred' statistic is incremented.
-
-*interval* [OPTIONS] 'interval' 'command'::
-Create a cron entry to execute 'command' every 'interval', where 'interval'
-is an arbitrary floating point duration with optional suffix 's' for
-seconds, 'm' for minutes, 'h' for hours and 'd' for days.
-Options:
-
- --name='STRING':::
- -n 'STRING':::
- Set a name for this cron entry to 'STRING'.
-
- --after='TIME':::
- -a 'TIME':::
- The first task will run after a delay of 'TIME' instead of 'interval'.
- After the first task the entry will continue to execute every 'interval'.
-
- --count='N':::
- -c 'N':::
- The entry will be run a total of 'N' times, then stopped.
-
- --options='LIST':::
- -o 'LIST':::
- The '--options' option allows a comma separated list of extra options to be
- passed to the flux-cron service. See EXTRA OPTIONS below.
-
- --preserve-env:::
- -E:::
- The '--preserve-env' option allows the current environment to be exported
- and used for the command being executed as part of the cron job. Normally,
- the broker environment is used.
-
- --working-dir='DIR':::
- -d 'DIR':::
- The '--working-dir' option allows the working directory to be set for the command
- being executed as part of the cron job. Normally, the working directory of
- the broker is used.
-
-*event* [OPTIONS] 'topic' 'command'::
-
-Create a cron entry to execute 'command' after every event matching 'topic'.
-
- --name='STRING':::
- -n 'STRING':::
- Set a name for this cron entry to 'STRING'.
-
- --nth='N':::
- -n 'N':::
- If '--nth' is given then 'command' will be run after each 'N' events.
-
- --count='N':::
- -c 'N':::
- With '--count', the entry is run 'N' times then stopped.
-
- --after='N':::
- -a 'N':::
- Run the first task only after 'N' matching events. Then run every event
- or 'N' events with '--nth'.
-
- --min-interval='T':::
- -i 'T':::
- Set the minimum interval at which two cron jobs for this event will be run.
- For example, with --min-interval of 1s, the cron job will be at most run
- every 1s, even if events are generated more quickly.
-
- --options='LIST':::
- -o 'LIST':::
- Set comma separated EXTRA OPTIONS for this cron entry.
-
- --preserve-env:::
- -E:::
- The '--preserve-env' option allows the current environment to be exported
- and used for the command being executed as part of the cron job. Normally,
- the broker environment is used.
-
- --working-dir='DIR':::
- -d 'DIR':::
- The '--working-dir' option allows the working directory to be set for the command
- being executed as part of the cron job. Normally, the working directory of
- the broker is used.
-
-*tab* [OPTIONS] ['file'] ::
-Process one or more lines containing crontab expressions from 'file'
-(stdin by default) Each valid crontab line will result in a new cron
-entry registered with the flux-cron service. The cron expression format
-supported by `flux cron tab` has 5 fields: 'minutes' (0-59), 'hours'
-(0-23), 'day of month' (1-31), 'month' (0-11), and 'day of week' (0-6).
-Everything after the day of week is considered a command to be run.
-
- --options='LIST':::
- -o 'LIST':::
- Set comma separated EXTRA OPTIONS for all cron entries.
-
-*at* [OPTIONS] 'string' 'command'
-Run 'command' at specific date and time described by 'string'
-
- --options='LIST':::
- -o 'LIST':::
- Set comma separated EXTRA OPTIONS for all cron entries.
-
- --preserve-env:::
- -E:::
- The '--preserve-env' option allows the current environment to be exported
- and used for the command being executed as part of the cron job. Normally,
- the broker environment is used.
-
- --working-dir='DIR':::
- -d 'DIR':::
- The '--working-dir' option allows the working directory to be set for the command
- being executed as part of the cron job. Normally, the working directory of
- the broker is used.
-*list*::
-Display a list of current entries registered with the cron module and
-their current state, last run time, etc.
-
-*stop* 'id'::
-Stop cron entry 'id'. The entry will remain in the cron entry list until
-deleted.
-
-*start* 'id'::
-Start a stopped cron entry 'id'.
-
-*delete* [--kill] 'id'::
-Purge cron entry 'id' from the flux-cron entry list. If '--kill' is used,
-kill any running task associated with entry 'id'.
-
-*dump* [--key=KEY] 'id'::
-Dump all information for cron entry 'id'. With '--key' print only the value
-for key 'KEY'. For a list of keys run 'flux cron dump ID'.
-
-EXTRA OPTIONS
--------------
-
-For `flux-cron` commands allowing `--options`, the following EXTRA OPTIONS
-are supported:
-
-timeout='N'::
-Set a timeout for tasks invoked for this cron entry to 'N' seconds, where
-N can be a floating point number. Default is no timeout.
-
-rank='R'::
-Set the rank on which to execute the cron command to 'R'. Default is rank 0.
-
-task-history-count='N'::
-Keep history for the last 'N' tasks invoked by this cron entry. Default is 1.
-
-stop-on-failure='N'::
-Automatically stop a cron entry if the failure count exceeds 'N'. If 'N' is
-zero (the default) then the cron entry will not be stopped on failure.
-
-
-OPERATION
----------
-The Flux cron module manages the set of currently configured cron
-jobs as a set of common entries, each with a unique ID supplied by
-a global sequence number and set of common attributes, options, and
-statistics. Basic attributes of a cron job include an optional 'name',
-the 'command' to execute on the entry's trigger, the current 'state' of
-the cron entry (stopped or not stopped), a 'repeat' count indicating the
-total number of times to execute the cron job before stopping, and the
-'type' of entry.
-
-All cron entries also support a less common list of options, which may
-be set at creation time via a comma-separated list of 'option=value'
-parameters passed to the '-o', '--option=OPTS'. These options are described
-in the EXTRA OPTIONS section at the end of this document.
-
-Currently, flux-cron supports only two types of entries. The 'interval'
-entry supports executing a command once every configured duration,
-optionally starting after a different time period. More detailed
-information about the interval type can be found in the documentation for
-the flux-cron 'interval' command above. The 'event' type entry supports
-running a command once every N events matching the configured event topic.
-More information about this type can be found in the documentation for
-'flux cron event'.
-
-The Flux cron module additionally keeps a common set of statistics for
-each entry, regardless of type . These include the creation time, last
-run time, and last time the cron entry was "started", as well a count of
-total number of times the command was executed and a count of successful
-and failed runs. Currently, the stats for a cron entry may be viewed via
-the 'flux cron dump' subcommand 'stats.*' output.
-
-When registered, cron entries are automatically 'started', meaning they
-are eligible to run the configured command when the trigger condition
-is met. Entries may be 'stopped', either by use of the 'flux cron stop'
-command, or if a 'stop-on-failure' value is set. Stopped entries are
-restarted using 'flux cron start', at which point counters used for
-repeat and stop-on-failure are reset.
-
-Stopped entries are kept in the flux cron until deleted with 'flux
-cron delete'. Active cron entries may also be deleted, with currently
-executing tasks optionally killed if the '--kill' option is provided.
-
-
-TASK EXECUTION
---------------
-
-As related above, cron entry commands are executed via the 'cmb.exec'
-service, which is a low level execution service offered outside of any
-scheduler control, described in more detail in the 'flux-exec(1)' man
-page.
-
-Standard output and error from tasks executed by the cron service are
-logged and may be viewed with 'flux-dmesg(1)'. If a cron task exits
-with non-zero status, or fails to launch under the 'cmb.exec' service,
-a message is logged and the failure is added to the failure stats.
-On task failure, the cron job is stopped if 'stop-on-failure' is set, and
-the current failure count exceeds the configured value. By default,
-'stop-on-failure' is not set.
-
-By default, flux-cron module keeps information for the last task executed
-for each cron entry. This information can be viewed either via the
-'flux cron list' or 'flux cron dump ID' subcommands. Data such as
-start and end time, exit status, rank, and PID for the task is available.
-The number of tasks kept for each cron entry may be individually tuned
-via the 'task-history-count' option, described in the EXTRA OPTIONS section.
-
-Commands are normally executed immediately on the interval or event
-trigger for which they are configured. However, if the 'sync-event'
-option is active on the cron module, tasks execution will be deferred
-until the next synchronization event. See the documentation above
-for 'flux cron sync' for more information.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-SEE ALSO
---------
-flux-exec(1), flux-dmesg(1)
diff --git a/doc/man1/flux-cron.rst b/doc/man1/flux-cron.rst
new file mode 100644
index 000000000000..8017fce1e9ff
--- /dev/null
+++ b/doc/man1/flux-cron.rst
@@ -0,0 +1,404 @@
+============
+flux-cron(1)
+============
+
+
+SYNOPSIS
+========
+
+| **flux** **cron** **tab** [*-E*] [*-d* *DIR*] [*-o* *OPT...*] [*file*]
+| **flux** **cron** **at** [*-E*] [*-d* *DIR*] [*-o* *OPT...*] *time* *command*
+| **flux** **cron** **event** [*-E*] [*-d* *DIR*] [*-o* *OPT...*] *topic* *command*
+| **flux** **cron** **interval** [*-E*] [*-d* *DIR*] [*-o* *OPT...*] *interval* *command*
+
+| **flux** **cron** **list**
+| **flux** **cron** **stop** *ids...*
+| **flux** **cron** **start** *ids...*
+| **flux** **cron** **delete** [*--kill*] *ids...*
+| **flux** **cron** **dump** [*--key=KEY*] *ids...*
+| **flux** **cron** **sync** [*--disable*] [*--epsilon=TIME*] *topic*
+
+
+DESCRIPTION
+===========
+
+The Flux cron service offers an interface for executing commands on
+triggers such as a time interval or Flux events. The service is
+implemented as a Flux broker module which, when loaded, manages
+a set of cron entries and uses the built-in *broker.exec* service to run
+a command associated with the entry each time the defined trigger is
+reached. As with :man1:`flux-exec`, these tasks run as direct children
+of the :man1:`flux-broker` and run outside of the control of any loaded
+job scheduling service.
+
+The :program:`flux cron` utility offers an interface to create, stop, start,
+query, and destroy these entries in the Flux cron service.
+
+For a detailed description of the cron service operation and how
+it executes tasks, see the `OPERATION`_ and `TASK EXECUTION`_ sections
+below.
+
+
+COMMANDS
+========
+
+The following sub-commands are available:
+
+tab
+---
+
+.. program:: flux cron tab
+
+Process one or more lines containing crontab expressions from *file*
+(stdin by default). Each valid crontab line will result in a new cron
+entry registered with the Flux cron service.
+
+Crontab lines have five standard fields, similar to :linux:man5:`crontab`:
+
+.. list-table::
+
+ * - minutes
+ - 0-59
+
+ * - hours
+ - 0-23
+
+ * - day of month
+ - 0-23
+
+ * - month
+ - 0-11
+
+ * - day of week
+ - 0-6
+
+Everything after the day of week is considered a command to be run.
+
+.. option:: -o, options=LIST
+
+ Set comma separated `EXTRA OPTIONS`_ for all cron entries.
+
+.. option:: -E, --preserve-env
+
+ Export the current environment to be used for the command being executed
+ as part of the cron job. Normally, the broker environment is used.
+
+.. option:: -d, --working-dir=DIR
+
+ Set the working directory for commands being executed as part
+ of the cron job. Normally, the working directory of the broker is used.
+
+at
+--
+
+.. program:: flux cron at
+
+Run *command* at specific date and time described by *time*. Any time
+string that can be parsed by :linux:man1:`date` is acceptable.
+
+.. option:: -o, options=LIST
+
+ Set comma separated `EXTRA OPTIONS`_ for all cron entries.
+
+.. option:: -E, --preserve-env
+
+ Export the current environment to be used for the command being executed
+ as part of the cron job. Normally, the broker environment is used.
+
+.. option:: -d, --working-dir=DIR
+
+ Set the working directory for the command being executed as part
+ of the cron job. Normally, the working directory of the broker is used.
+
+event
+-----
+
+.. program:: flux cron event
+
+Create a cron entry to execute *command* after every event matching *topic*.
+
+.. option:: -N, --name=STRING
+
+ Set a name for this cron entry to *STRING*.
+
+.. option:: -n, --nth=N
+
+ If :option:`--nth` is given then *command* will be run after each *N* events.
+
+.. option:: -c, --count=N
+
+ With :option:`--count`, the entry is run *N* times then stopped.
+
+.. option:: -a, --after=N
+
+ Run the first task only after *N* matching events. Then run every event
+ or *N* events with :option:`--nth`.
+
+.. option:: -i, --min-interval=T
+
+ Set the minimum interval at which two cron jobs for this event will be run.
+ For example, with :option:`--min-interval` of 1s, the cron job will be
+ at most run every 1s, even if events are generated more quickly.
+
+.. option:: -o, --options=LIST
+
+ Set comma separated `EXTRA OPTIONS`_ for this cron entry.
+
+.. option:: -E, --preserve-env
+
+ Export the current environment to be used for the command being executed
+ as part of the cron job. Normally, the broker environment is used.
+
+.. option:: -d, --working-dir=DIR
+
+ Set the working directory for the command being executed as part
+ of the cron job. Normally, the working directory of the broker is used.
+
+interval
+--------
+
+.. program:: flux cron interval
+
+Create a cron entry to execute *command* every *interval*, where *interval*
+is an arbitrary floating point duration with optional suffix *s* for
+seconds, *m* for minutes, *h* for hours and *d* for days. If no suffix is
+specified, seconds is assumed.
+
+.. option:: -n, --name=STRING
+
+ Set a name for this cron entry to *STRING*.
+
+.. option:: -a, --after=TIME
+
+ The first task will run after a delay of *TIME* instead of *interval*, where
+ *TIME* is an arbitrary floating point duration specified in the same format
+ as *interval*. After the first task the entry will continue to execute
+ every *interval*.
+
+.. option:: -c, --count=N
+
+ The entry will be run a total of *N* times, then stopped.
+
+.. option:: -o, --options=LIST
+
+ Set comma separated `EXTRA OPTIONS`_ for this cron entry.
+
+.. option:: -E, --preserve-env
+
+ Export the current environment to be used for the command being executed
+ as part of the cron job. Normally, the broker environment is used.
+
+.. option:: -d, --working-dir=DIR
+
+ Set the working directory set for the command being executed as part
+ of the cron job. Normally, the working directory of the broker is used.
+
+
+list
+----
+
+.. program:: flux cron list
+
+Display a list of current entries registered with the cron module and
+their current state, last run time, etc.
+
+stop
+----
+
+.. program:: flux cron stop
+
+Stop cron entry *id*. The entry will remain in the cron entry list until
+deleted.
+
+start
+-----
+
+.. program:: flux cron start
+
+Start a stopped cron entry *id*.
+
+delete
+------
+
+.. program:: flux cron delete
+
+Purge cron entry *id* from the cron entry list.
+
+.. option:: -k, --kill
+
+Kill any running task associated with entry *id*.
+
+dump
+----
+
+.. program:: flux cron dump
+
+Dump all information for cron entry *id*.
+
+.. option:: -k, --key=KEY
+
+Print only the value for key *KEY*.
+
+For a list of keys run :option:`flux cron dump ID`.
+
+sync
+----
+
+.. program flux cron sync
+
+Query and modify the current **sync-event** behavior for the cron module.
+If a sync-event is set, the cron module will defer all task execution
+until an event matching the sync-event *topic* is received.
+
+Without any *topic* supplied on command line, :program:`flux cron sync`
+displays the current setting for sync.
+
+If a task is deferred due to sync-event, the *stats.deferred* statistic
+is incremented.
+
+.. option:: -e, --epsilon=TIME
+
+ Set amount of time after a *sync-event* that jobs are still allowed to
+ be run. With this option, the cron module will **not** delay task execution
+ if the task is normally scheduled to run within *delay* of the matching
+ event.
+
+.. option:: -d, --disable
+
+ Disable the cron *sync-event*.
+
+
+EXTRA OPTIONS
+=============
+
+.. program:: flux cron tab
+
+For :program:`flux cron` commands allowing :option:`--options`, the following
+extra options are supported:
+
+.. option:: -o timeout=N
+
+ Set a timeout for tasks invoked for this cron entry to *N* seconds, where
+ N can be a floating point number. Default is no timeout.
+
+.. option:: -o rank=R
+
+ Set the rank on which to execute the cron command to *R*. Default is rank 0.
+
+.. option:: -o task-history-count=N
+
+ Keep history for the last *N* tasks invoked by this cron entry. Default is 1.
+
+.. option:: -o stop-on-failure=N
+
+ Automatically stop a cron entry if the failure count exceeds *N*. If *N* is
+ zero (the default) then the cron entry will not be stopped on failure.
+
+OPERATION
+=========
+
+The Flux cron module manages the set of currently configured cron
+jobs as a set of common entries, each with a unique ID supplied by
+a global sequence number and set of common attributes, options, and
+statistics. Basic attributes of a cron job include an optional *name*,
+the *command* to execute on the entry's trigger, the current *state* of
+the cron entry (stopped or not stopped), a *repeat* count indicating the
+total number of times to execute the cron job before stopping, and the
+*type* of entry.
+
+All cron entries also support a less common list of options, which may
+be set at creation time via a comma-separated list of *option=value*
+parameters passed to :option:`-o, --option=OPTS`. These options are described
+in the EXTRA OPTIONS section at the end of this document.
+
+Currently, Flux cron supports only two types of entries. The *interval*
+entry supports executing a command once every configured duration,
+optionally starting after a different time period. More detailed
+information about the interval type can be found in the documentation for
+the :program:`flux cron interval` command above. The *event* type entry supports
+running a command once every N events matching the configured event topic.
+More information about this type can be found in the documentation for
+:program:`flux cron event`.
+
+The Flux cron module additionally keeps a common set of statistics for
+each entry, regardless of type . These include the creation time, last
+run time, and last time the cron entry was "started", as well a count of
+total number of times the command was executed and a count of successful
+and failed runs. Currently, the stats for a cron entry may be viewed via
+the *flux cron dump* subcommand *stats.\** output.
+
+When registered, cron entries are automatically *started*, meaning they
+are eligible to run the configured command when the trigger condition
+is met. Entries may be *stopped*, either by use of the :program:`flux cron stop`
+command, or if a *stop-on-failure* value is set. Stopped entries are
+restarted using :program:`flux cron start`, at which point counters used for
+repeat and stop-on-failure are reset.
+
+Stopped entries are kept in the flux cron until deleted with
+:program:`flux cron delete`. Active cron entries may also be deleted, with
+currently executing tasks optionally killed if the :option:`--kill` option is
+provided.
+
+
+TASK EXECUTION
+==============
+
+As related above, cron entry commands are executed via the *broker.exec*
+service, which is a low level execution service offered outside of any
+scheduler control, described in more detail in the *flux-exec(1)* man
+page.
+
+Standard output and error from tasks executed by the cron service are
+logged and may be viewed with :man1:`flux-dmesg`. If a cron task exits
+with non-zero status, or fails to launch under the *broker.exec* service,
+a message is logged and the failure is added to the failure stats.
+On task failure, the cron job is stopped if *stop-on-failure* is set, and
+the current failure count exceeds the configured value. By default,
+*stop-on-failure* is not set.
+
+By default, the Flux cron module keeps information for the last task executed
+for each cron entry. This information can be viewed either via the
+:program:`flux cron list` or :program:`flux cron dump ID` subcommands. Data
+such as start and end time, exit status, rank, and PID for the task is
+available. The number of tasks kept for each cron entry may be individually
+tuned via the :option:`--task-history-count` option, described in the
+EXTRA OPTIONS section.
+
+Commands are normally executed immediately on the interval or event
+trigger for which they are configured. However, if the :option:`sync`
+option is active on the cron module, tasks execution will be deferred
+until the next synchronization event. See the documentation above
+for :program:`flux cron sync` for more information.
+
+
+EXAMPLES
+========
+
+Run a script every hour
+
+::
+
+ $ flux cron interval 1h my_script.sh
+ interval: cron-1 created
+
+Run a script only when the event "cron.trigger" is published
+
+::
+
+ $ flux cron event cron.trigger my_script.sh
+ event: cron-2 created
+ ...
+ $ flux event pub cron.trigger
+
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-exec`, :man1:`flux-dmesg`
diff --git a/doc/man1/flux-dmesg.adoc b/doc/man1/flux-dmesg.adoc
deleted file mode 100644
index fb6f8bd2fe4e..000000000000
--- a/doc/man1/flux-dmesg.adoc
+++ /dev/null
@@ -1,63 +0,0 @@
-// flux-help-description: manipulate broker log ring buffer
-FLUX-DMESG(1)
-=============
-:doctype: manpage
-
-
-NAME
-----
-flux-dmesg - access broker ring buffer
-
-
-SYNOPSIS
---------
-*flux* *dmesg* ['OPTIONS']
-
-
-DESCRIPTION
------------
-
-Each broker rank maintains a circular buffer of log entries
-which can be printed using flux-dmesg(1).
-
-
-OPTIONS
--------
-
-*-C, --clear*::
-Clear the ring buffer.
-
-*-c, --read-clear*::
-Clear the ring buffer after printing its contents.
-
-*-f, --follow*::
-After printing the contents of the ring buffer, wait for new entries
-and print them as they arrive.
-
-
-EXAMPLES
---------
-
-To dump the ring buffer on all ranks
-
- $ flux exec flux dmesg | sort
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-flux-setattr(1), flux-broker-attributes(7)
diff --git a/doc/man1/flux-dmesg.rst b/doc/man1/flux-dmesg.rst
new file mode 100644
index 000000000000..9872013cf0ad
--- /dev/null
+++ b/doc/man1/flux-dmesg.rst
@@ -0,0 +1,76 @@
+=============
+flux-dmesg(1)
+=============
+
+
+SYNOPSIS
+========
+
+**flux** **dmesg** [*OPTIONS*]
+
+
+DESCRIPTION
+===========
+
+.. program:: flux dmesg
+
+Each broker rank maintains a circular buffer of log entries
+which can be printed using :program:`flux dmesg`.
+
+
+OPTIONS
+=======
+
+.. option:: -C, --clear
+
+ Clear the ring buffer.
+
+.. option:: -c, --read-clear
+
+ Clear the ring buffer after printing its contents.
+
+.. option:: -f, --follow
+
+ After printing the contents of the ring buffer, wait for new entries
+ and print them as they arrive.
+
+.. option:: -n, --new
+
+ Follow only new log entries.
+
+.. option:: -H, --human
+
+ Display human-readable output. See also :option:`--color` and
+ :option:`--delta`.
+
+.. option:: -d, --delta
+
+ With :option:`--human`, display the time delta between messages instead
+ of a relative offset since the last absolute timestamp.
+
+.. option:: -L, --color[=WHEN]
+
+ Colorize output. The optional argument *WHEN* can be *auto*, *never*,
+ or *always*. If *WHEN* is omitted, it defaults to *always*. The default
+ value when the :option:`--color` option is not used is *auto*.
+
+EXAMPLES
+========
+
+To dump the ring buffer on all ranks
+
+::
+
+ $ flux exec flux dmesg | sort
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-setattr`, :man7:`flux-broker-attributes`
diff --git a/doc/man1/flux-dump.rst b/doc/man1/flux-dump.rst
new file mode 100644
index 000000000000..501771e437c5
--- /dev/null
+++ b/doc/man1/flux-dump.rst
@@ -0,0 +1,136 @@
+============
+flux-dump(1)
+============
+
+
+SYNOPSIS
+========
+
+**flux** **dump** [*OPTIONS*] *OUTFILE*
+
+
+DESCRIPTION
+===========
+
+.. program flux dump
+
+The :program:`flux dump` command writes a KVS snapshot to a portable archive
+format, usually read by :man1:`flux-restore`.
+
+The snapshot source is the primary namespace of the current KVS root by default.
+If :option:`--checkpoint` is specified, the snapshot source is the last KVS
+checkpoint written to the content backing store.
+
+The archive is a file path or *-* for standard output. If standard output,
+the format is POSIX *ustar* with no compression. Otherwise the format is
+determined by the file extension. The list of valid extensions depends on the
+version of :linux:man3:`libarchive` used to build Flux, but modern versions
+support:
+
+.tar
+ POSIX *ustar* format, compatible with :linux:man1:`tar`.
+
+.tgz, .tar.gz
+ POSIX *ustar* format, compressed with :linux:man1:`gzip`.
+
+.tar.bz2
+ POSIX *ustar* format, compressed with :linux:man1:`bzip2`.
+
+.tar.xz
+ POSIX *ustar* format, compressed with :linux:man1:`xz`.
+
+.zip
+ ZIP archive, compatible with :linux:man1:`unzip`.
+
+.cpio
+ POSIX CPIO format, compatible with :linux:man1:`cpio`.
+
+.iso
+ ISO9660 CD image
+
+
+OPTIONS
+=======
+
+.. option:: -h, --help
+
+ Summarize available options.
+
+.. option:: -v, --verbose
+
+ List keys on stderr as they are dumped instead of a periodic count of
+ dumped keys.
+
+.. option:: -q, --quiet
+
+ Don't show periodic count of dumped keys on stderr.
+
+.. option:: --checkpoint
+
+ Generate snapshot from the latest checkpoint written to the content
+ backing store, instead of from the current KVS root.
+
+.. option:: --no-cache
+
+ Bypass the broker content cache and interact directly with the backing
+ store. This may be slightly faster, depending on how frequently the same
+ content blobs are referenced by multiple keys.
+
+.. option:: --ignore-failed-read
+
+ If KVS metadata is encountered that references nonexistent blobrefs
+ (for example after a disk full event), print an error but skip over the
+ KVS key and treat it as a warning. Without this option, content load
+ failures are treated as immediate fatal errors.
+
+
+OTHER NOTES
+===========
+
+KVS commits are atomic and propagate to the root of the namespace. Because of
+this, when :program:`flux dump` archives a snapshot of a live system, it
+reflects one point in time, and does not include any changes committed while
+the dump is in progress.
+
+Since :program:`flux dump` generates the archive by interacting directly with
+the content store, the :option:`--checkpoint` option may be used to dump the
+most recent state of the KVS when the KVS module is not loaded.
+
+Only regular values and symbolic links are dumped to the archive. Directories
+are not dumped as independent objects, so empty directories are omitted from
+the archive.
+
+KVS symbolic links represent the optional namespace component in the target
+as a *NAME::* prefix.
+
+The KVS path separator is converted to the UNIX-compatible slash so that the
+archive can be unpacked into a file system if desired.
+
+The modification time of files in the archive is set to the time that
+:program:`flux dump` is started if dumping the current KVS root, or to the
+timestamp of the checkpoint if :option:`--checkpoint` is used.
+
+The owner and group of files in the archive are set to the credentials of the
+user that ran :program:`flux-dump`.
+
+The mode of files in the archive is set to 0644.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_10`
+
+:doc:`rfc:spec_11`
+
+
+SEE ALSO
+========
+
+:man1:`flux-restore`, :man1:`flux-kvs`
diff --git a/doc/man1/flux-env.adoc b/doc/man1/flux-env.adoc
deleted file mode 100644
index 2c899afb35f5..000000000000
--- a/doc/man1/flux-env.adoc
+++ /dev/null
@@ -1,40 +0,0 @@
-// flux-help-description : Print or run inside a Flux environment
-FLUX-ENV(1)
-===========
-:doctype: manpage
-
-
-NAME
-----
-flux-env - Print the flux environment or execute a command inside it
-
-
-SYNOPSIS
---------
-*flux* *env* [COMMAND]
-
-
-DESCRIPTION
------------
-flux-env(1) dumps a list of all environment variables as set by flux if run
-without a command, when run with a command the environment is set and the
-command is run as it would be by the ENV(1) utility.
-
-//OPTIONS
-//-------
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
diff --git a/doc/man1/flux-env.rst b/doc/man1/flux-env.rst
new file mode 100644
index 000000000000..4c9ce14764ce
--- /dev/null
+++ b/doc/man1/flux-env.rst
@@ -0,0 +1,26 @@
+.. flux-help-description : Print or run inside a Flux environment
+
+===========
+flux-env(1)
+===========
+
+
+SYNOPSIS
+========
+
+**flux** **env** [COMMAND]
+
+
+DESCRIPTION
+===========
+
+:program:`flux env` dumps a list of all environment variables as set by
+:man1:`flux` if run without a command, when run with a command the
+environment is set and the command is run as it would be by the
+:linux:man1:`env` utility.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
diff --git a/doc/man1/flux-event.adoc b/doc/man1/flux-event.adoc
deleted file mode 100644
index 832fb50c38c8..000000000000
--- a/doc/man1/flux-event.adoc
+++ /dev/null
@@ -1,63 +0,0 @@
-// flux-help-include: true
-FLUX-EVENT(1)
-=============
-:doctype: manpage
-
-
-NAME
-----
-flux-event - Send and receive Flux events
-
-
-SYNOPSIS
---------
-*flux* *event* 'COMMAND' ['OPTIONS']
-
-
-DESCRIPTION
------------
-Flux events are messages that are broadcast throughout the Flux instance
-with publish/subscribe semantics. Each event message has a _topic string_
-and an optional _payload_.
-
-Subscriptions are by topic string. A subscription topic of length _N_
-matches an event if the first _N_ characters of the event topic
-are identical to that of the subscription. For example the event topic
-'a.b.c' is matched by the subscription topic 'a.b.c', 'a.b', or 'a'.
-A subscription to the empty string matches all events.
-
-COMMANDS
---------
-*pub* [-r] [-l] [-s] [-p] 'topic' ['payload']::
-Publish an event with optional payload. If payload is specified,
-it is interpreted as raw if the '-r' option is used, otherwise it is
-interpreted as JSON. If the payload spans multiple arguments,
-the arguments are concatenated with one space between them.
-If '-s' is specified, wait for the event's sequence number to be
-assigned before exiting.
-If '-l' is specified, subscribe to the published event and wait for
-it to be received before exiting. '-p' causes the privacy flag to
-be set on the published event.
-
-*sub* '[-c N]' ['topic'] ['topic'...]::
-Subscribe to events matching the topic string(s) provided on the
-command line. If none are specified, subscribe to all events.
-If '-c N' is specified, print the first 'N' events on stdout and exit;
-otherwise continue printing events until a signal is received.
-Events are displayed one per line: the topic string, followed by a tab,
-followed by the payload, if any.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
diff --git a/doc/man1/flux-event.rst b/doc/man1/flux-event.rst
new file mode 100644
index 000000000000..14c8b3fc104e
--- /dev/null
+++ b/doc/man1/flux-event.rst
@@ -0,0 +1,90 @@
+=============
+flux-event(1)
+=============
+
+
+SYNOPSIS
+========
+
+| **flux** **event** **pub** [*--raw*] [*--synchronous*] [*--private*] *topic* [*payload*]
+| **flux** **event** **sub** [*--count=N*] *topic...*
+
+
+DESCRIPTION
+===========
+
+Flux events are messages that are broadcast throughout the Flux instance
+with publish/subscribe semantics. Each event message has a *topic string*
+and an optional *payload*.
+
+Subscriptions are by topic string. A subscription topic of length *N*
+matches an event if the first *N* characters of the event topic
+are identical to that of the subscription. For example the event topic
+*a.b.c* is matched by the subscription topic *a.b.c*, *a.b*, or *a*.
+A subscription to the empty string matches all events.
+
+
+COMMANDS
+========
+
+pub
+---
+
+.. program:: flux event pub
+
+Publish an event on *topic* with optional *payload*. If payload is specified,
+it is interpreted as JSON unless other options are selected. If the payload
+spans multiple arguments, the arguments are concatenated with one space
+between them.
+
+.. option:: -r, --raw
+
+ Interpret event payload as raw instead of JSON.
+
+.. option:: -s, --synchronous
+
+ Wait for the event's sequence number to be assigned before exiting.
+
+.. option:: -l, --loopback
+
+ Subscribe to the published event and wait for it to be received before
+ exiting.
+
+.. option:: -p, --private
+
+ Set the privacy flag on the published event.
+
+Example: publish an event with topic ``foo.hello`` and no payload::
+
+ flux event pub foo.hello
+
+sub
+---
+
+.. program:: flux event sub
+
+Subscribe to events matching the topic string(s) provided on the
+command line. If none are specified, subscribe to all events.
+Events are displayed one per line: the topic string, followed by a tab,
+followed by the payload, if any.
+
+.. option:: -c, --count=N
+
+ Print the first *N* events on stdout and exit. Otherwise events are
+ processed until a signal is received.
+
+Example: subscribe to all events with topic prefix of ``foo.``::
+
+ flux event sub foo.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_3`
diff --git a/doc/man1/flux-exec.adoc b/doc/man1/flux-exec.adoc
deleted file mode 100644
index 743b441a8874..000000000000
--- a/doc/man1/flux-exec.adoc
+++ /dev/null
@@ -1,85 +0,0 @@
-// flux-help-include: true
-FLUX-EXEC(1)
-============
-:doctype: manpage
-
-
-NAME
-----
-flux-exec - Execute processes across flux ranks
-
-
-SYNOPSIS
---------
-*flux* *exec* [--noinput] ['--labelio] ['--dir=DIR'] ['--rank=NODESET'] ['--verbose'] COMMANDS...
-
-
-DESCRIPTION
------------
-flux-exec(1) runs commands across one or more flux-broker ranks using
-the 'cmb.exec' service. The commands are executed as direct children
-of the broker, and the broker handles buffering stdout and stderr and
-sends the output back to flux-exec(1) which copies output to its own
-stdout and stderr.
-
-On receipt of SIGINT and SIGTERM signals, flux-exec(1) shall forward
-the received signal to all currently running remote processes.
-
-In the event subprocesses are hanging or ignoring SIGINT, two SIGINT
-signals (typically sent via Ctrl+C) in short succession can force
-flux-exec(1) to exit.
-
-flux-exec(1) is meant as an administrative and test utility, and cannot
-be used to launch Flux jobs.
-
-EXIT STATUS
------------
-In the case that all processes are successfully launched, the exit status
-of flux-exec(1) is the largest of the remote process exit codes.
-
-If a non-existent rank is targeted, flux-exec(1) will return with
-code 68 (EX_NOHOST from sysexits.h).
-
-If one or more remote commands are terminated by a signal, then flux-exec(1)
-exits with exit code 128+signo.
-
-OPTIONS
--------
-
-*-l, --labelio*::
-Label lines of output with the source RANK.
-
-*-n, --noinput*::
-Do not attempt to forward stdin. Send EOF to remote process stdin.
-
-*-d, --dir*'=DIR'::
-Set the working directory of remote 'COMMANDS' to 'DIR'. The default is to
-propagate the current working directory of flux-exec(1).
-
-*-r, --rank*'=NODESET'::
-Target specific ranks in 'NODESET'. Default is to target "all" ranks.
-See NODESET FORMAT below for more information.
-
-*-v, --verbose*::
-Run with more verbosity.
-
-
-NODESET FORMAT
---------------
-include::NODESET.adoc[]
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
diff --git a/doc/man1/flux-exec.rst b/doc/man1/flux-exec.rst
new file mode 100644
index 000000000000..ec42202fca5e
--- /dev/null
+++ b/doc/man1/flux-exec.rst
@@ -0,0 +1,128 @@
+============
+flux-exec(1)
+============
+
+SYNOPSIS
+========
+
+**flux** **exec** [*--noinput*] [*--label-io*] [*âdir=DIR*] [*--rank=IDSET*] [*--verbose*] *COMMAND...*
+
+DESCRIPTION
+===========
+
+.. program:: flux exec
+
+:program:`flux exec` remotely executes one or more copies of *COMMAND*,
+similar to :linux:man1:`pdsh`. It bypasses the scheduler and is intended
+for launching administrative commands or tool daemons, not for launching
+parallel jobs. For that, see :man1:`flux-run`.
+
+By default, *COMMAND* runs across all :man1:`flux-broker` processes. If the
+:option:`--jobid` option is specified, the commands are run across a job's
+:man1:`flux-shell` processes. Normally there is only one broker process per
+node, and one job shell per broker, meaning that one copy of *COMMAND* is
+is executed per node, but in unusual cases it could mean more (e.g. if the
+Flux instance was started with multiple brokers per node).
+
+Standard output and standard error of the remote commands are captured
+and combined on the :program:`flux exec` standard output and standard error.
+Standard input of :program:`flux exec` is captured and broadcast to standard
+input of the remote commands.
+
+On receipt of SIGINT and SIGTERM signals, :program:`flux exec` forwards
+the received signal to the remote processes. When standard input of
+:program:`flux exec` is a terminal, :kbd:`Control-C` may be used to send
+SIGINT. Two of those in short succession can force :program:`flux exec`
+to exit in the event that remote processes are hanging.
+
+OPTIONS
+=======
+
+.. option:: -l, --label-io
+
+ Label lines of output with the source broker RANK. This option is not
+ affected by :option:`--jobid`.
+
+.. option:: -n, --noinput
+
+ Do not attempt to forward stdin. Send EOF to remote process stdin.
+
+.. option:: -d, --dir=DIR
+
+ Set the working directory of remote *COMMAND* to *DIR*. The default is to
+ propagate the current working directory of flux-exec(1).
+
+.. option:: -r, --rank=IDSET
+
+ Target specific ranks, where *IDSET* is a set of zero-origin node ranks in
+ RFC 22 format. If :option:`--jobid` is specified, the ranks are interpreted
+ as an index into the list of nodes assigned to the job. Otherwise, they
+ refer to the nodes assigned to the Flux instance.
+
+ The default is to target all ranks. As a special case, :option:`--rank=all`
+ is accepted and behaves the same as the default.
+
+.. option:: -x, --exclude=IDSET
+
+ Exclude specific ranks. *IDSET* is as described in :option:`--rank`.
+
+.. option:: -j, --jobid=JOBID
+
+ Run *COMMAND* on the nodes allocated to *JOBID* instead of the nodes
+ assigned to the Flux instance.
+
+ This uses the exec service embedded in :man1:`flux-shell` rather than
+ :man1:`flux-broker`.
+
+ The interpretation of :option:`--rank` and :option:`--exclude` is adjusted
+ as noted in their descriptions. For example, :option:`flux exec -j ID -r 0`
+ will run only on the first node assigned to *JOBID*, and
+ :option:`flux exec -j ID -x 0` will run on all nodes assigned to *JOBID*
+ except the first node.
+
+ This option is only available when the job owner is the same as the Flux
+ instance owner.
+
+.. option:: -v, --verbose
+
+ Run with more verbosity.
+
+.. option:: -q, --quiet
+
+ Suppress extraneous output (e.g. per-rank error exit status).
+
+.. option:: --with-imp
+
+ Prepend the full path to :program:`flux-imp run` to *COMMAND*. This option
+ is mostly meant for testing or as a convenience to execute a configured
+ ``prolog`` or ``epilog`` command under the IMP.
+
+CAVEATS
+=======
+
+In a multi-user flux instance, access to the rank 0 broker execution
+service is restricted to requests that originate from the local broker.
+Therefore, :program:`flux exec` (without :option:`--jobid`) must be run
+from the rank 0 broker if rank 0 is included in the target *IDSET*.
+
+EXIT STATUS
+===========
+
+In the case that all processes are successfully launched, the exit status
+of :program:`flux exec` is the largest of the remote process exit codes.
+
+If a non-existent rank is targeted, :program:`flux exec` will return with
+code 68 (EX_NOHOST from sysexits.h).
+
+If one or more remote commands are terminated by a signal, then
+:program:`flux exec` exits with exit code 128+signo.
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_22`
diff --git a/doc/man1/flux-getattr.adoc b/doc/man1/flux-getattr.adoc
deleted file mode 100644
index 13c9e8afa677..000000000000
--- a/doc/man1/flux-getattr.adoc
+++ /dev/null
@@ -1,57 +0,0 @@
-// flux-help-command: get,set,lsattr
-// flux-help-description: Access, modify, and list broker attributes
-FLUX-GETATTR(1)
-===============
-:doctype: manpage
-
-
-NAME
-----
-flux-getattr, flux-setattr, flux-lsattr - access broker attributes
-
-
-SYNOPSIS
---------
-*flux* *getattr* 'name'
-
-*flux* *setattr* 'name' 'value'
-
-*flux* *setattr* ['--expunge'] 'name'
-
-*flux* *lsattr* ['--values']
-
-
-DESCRIPTION
------------
-
-Flux broker attributes are both a simple, general-purpose key-value
-store with scope limited to the local broker rank, and a method for the
-broker to export information needed by Flux comms modules and
-utilities.
-
-flux-getattr(1) retrieves the value of an attribute.
-
-flux-setattr(1) assigns a new value to an attribute, or optionally
-removes an attribute.
-
-flux-lsattr(1) lists attribute names, optionally with their values.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-flux_attr_get(3), flux-broker-attributes(7)
diff --git a/doc/man1/flux-getattr.rst b/doc/man1/flux-getattr.rst
new file mode 100644
index 000000000000..099632ff1eab
--- /dev/null
+++ b/doc/man1/flux-getattr.rst
@@ -0,0 +1,67 @@
+===============
+flux-getattr(1)
+===============
+
+
+SYNOPSIS
+========
+
+| **flux** **getattr** *name*
+| **flux** **setattr** *name* *value*
+| **flux** **lsattr** [*--values*]
+
+
+DESCRIPTION
+===========
+
+The Flux broker attribute subsystem provides a primitive key-value
+configuration mechanism for the broker. Attributes can be set on the
+broker command line with :option:`flux broker --setattr`, then read,
+written, or listed using :program:`flux getattr`, :program:`flux setattr`,
+or :program:`flux lsattr` after the broker is running.
+
+Attribute scope is local to an individual broker. That is, broker ranks
+may have different values for a given attribute.
+
+:man7:`flux-broker-attributes` provides a catalog of attributes.
+
+COMMANDS
+========
+
+getattr
+-------
+
+.. program:: flux getattr
+
+:program:`flux getattr` retrieves the value of an attribute.
+
+setattr
+-------
+
+.. program:: flux setattr
+
+:program:`flux setattr` assigns a value to an attribute. If the attribute
+does not exist, it is created.
+
+lsattr
+------
+
+.. program:: flux lsattr
+
+:program:`flux lsattr` lists attributes.
+
+.. option:: -v, --values
+
+ List the attribute values too.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_attr_get`, :man7:`flux-broker-attributes`
diff --git a/doc/man1/flux-hostlist.rst b/doc/man1/flux-hostlist.rst
new file mode 100644
index 000000000000..29a5dfe78c4a
--- /dev/null
+++ b/doc/man1/flux-hostlist.rst
@@ -0,0 +1,235 @@
+.. flux-help-section: other
+
+================
+flux-hostlist(1)
+================
+
+SYNOPSIS
+========
+
+**flux** **hostlist** [*OPTIONS*] [*SOURCES*]
+
+DESCRIPTION
+===========
+
+.. program:: flux hostlist
+
+:program:`flux hostlist` takes zero or more *SOURCES* of host lists on the
+command line and concatenates them by default into a single RFC 29 Hostlist.
+
+*SOURCES* can optionally be combined by various set operations, for example
+to find the intersection, difference, or to subtract hostlists.
+
+SOURCES
+=======
+
+Valid *SOURCES* of hostlist information include:
+
+instance
+ hosts from the broker ``hostlist`` attribute
+
+jobid
+ hosts assigned to a job.
+
+local
+ *jobid* from ``FLUX_JOB_ID`` environment variable if set, otherwise
+ *instance*
+
+avail[able]
+ *instance* hostlist minus those nodes down or drained
+
+stdin or ``-``
+ read a list of hosts on stdin
+
+hosts
+ a literal RFC 29 Hostlist
+
+The default source is *stdin*.
+
+OPTIONS
+=======
+
+.. option:: -e, --expand
+
+ Expand hostlist result using the defined output delimiter. Default is
+ space-delimited.
+
+.. option:: -d, --delimiter=S
+
+ Set the delimiter for :option:`--expand` to string *S*.
+
+.. option:: -c, --count
+
+ Emit the number of hosts in the result hostlist instead of the hostlist
+ itself.
+
+.. option:: -n, --nth=IDS
+
+ Output only the hosts at indices *IDS* (*-IDS* to index from the end),
+ where *IDS* is a valid RFC 22 idset (e.g. '0' will return the first host,
+ '0-1' will return the first and second, '-1' returns the last host). The
+ command will fail if any id in *IDS* is not a valid index.
+
+.. option:: -L, --limit=N
+
+ Output at most *N* hosts (*-N* to output the last *N* hosts).
+
+.. option:: -S, --sort
+
+ Display sorted result.
+
+.. option:: -u, --union, --unique
+
+ Return only unique hosts. This implies :option:`--sort`. Without any
+ other manipulation options, this is equivalent to returning the set
+ union of all provided hosts. (By default, all inputs are concatenated).
+
+.. option:: -x, --exclude=HOSTS|IDS
+
+ Exclude all hosts in *HOSTS* or indices in idset *IDS* from the result.
+ It is not an error if any hosts or indices do not exist in the target
+ hostlist.
+
+.. option:: -i, --intersect
+
+ Return the set intersection of all hostlists.
+
+.. option:: -m, --minus
+
+ Subtract all hostlists from the first.
+
+.. option:: -X, --xor
+
+ Return the symmetric difference of all hostlists.
+
+.. option:: -f, --fallback
+
+ If an argument to :command:`flux-hostlist` is a single hostname, and the
+ hostname can be interpreted as a valid Flux jobid (e.g. starts with ``f``
+ and otherwise contains valid base58 characters like ``fuzzy`` or ``foo1``),
+ then the command may fail with::
+
+ flux-hostlist: ERROR: job foo1 not found
+
+ With the :option:`--fallback` option arguments that appear to be jobids that
+ are not found are treated as hostnames, e.g.::
+
+ $ flux hostlist --fallback foo1 foo2
+ foo[1-2]
+
+.. option:: -l, --local
+
+ Change the default input source to "local". This is a shorter way to
+ specify ``flux hostlist local``.
+
+.. option:: -q, --quiet
+
+ Suppress output and exit with a nonzero exit code if the hostlist is empty.
+
+EXAMPLES
+========
+
+Create host file for the current job or instance if running in an initial
+program:
+
+::
+
+ $ flux hostlist -led'\n' >hostfile
+
+Launch an MPI program using :program:`mpiexec.hydra` from within a batch
+script:
+
+::
+
+ #!/bin/sh
+ mpiexec.hydra -launcher ssh -hosts "$(flux hostlist -le)" mpi_hello
+
+List the hosts for one job: (Note: this is the same as
+:command:`flux jobs -no {nodelist} JOBID`)
+
+::
+
+ $ flux hostlist JOBID
+ host[1-2]
+
+List the hosts for one job, excluding the first node:
+
+::
+
+ $ flux hostlist -x 0 JOBID
+
+List the unordered, unique hosts for multiple jobs:
+
+::
+
+ $ flux hostlist -u JOBID1 JOBID2 JOBID3
+ host[1-2,4]
+
+Determine if any failed jobs shared common nodes:
+
+::
+
+ $ flux hostlist --intersect $(flux jobs -f failed -no {id})
+ host4
+
+Determine if a given host appeared the last submitted job:
+
+::
+
+ if flux hostlist -q -i $(flux job last) host1; then
+ echo host1 was part of your last job
+ fi
+
+
+Count the number of currently available hosts:
+
+::
+
+ $ flux hostlist --count avail
+ 4
+
+List all the hosts on which a job named 'myapp' ran:
+
+::
+
+ $ flux hostlist --union $(flux pgrep myapp)
+ host[2,4-5]
+
+List all hosts in the current instance which haven't had a job assigned
+in the last 100 jobs:
+
+::
+
+ $ flux hostlist --minus instance $(flux jobs -c 100 -ano {id})
+ host0
+
+EXIT STATUS
+===========
+
+0
+ Successful operation
+
+1
+ One or more *SOURCES* were invalid, an invalid index was specified to
+ :option:`--nth`, or :option:`--quiet` was used and the result hostlist
+ was empty.
+
+2
+ Invalid option specified or other command line error
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_29`
+:doc:`rfc:spec_22`
+
+
+SEE ALSO
+========
+
+:man1:`flux-getattr`, :man1:`flux-jobs`, :man7:`flux-broker-attributes`
diff --git a/doc/man1/flux-housekeeping.rst b/doc/man1/flux-housekeeping.rst
new file mode 100644
index 000000000000..1db5df23c16c
--- /dev/null
+++ b/doc/man1/flux-housekeeping.rst
@@ -0,0 +1,185 @@
+====================
+flux-housekeeping(1)
+====================
+
+
+SYNOPSIS
+========
+
+| **flux** **housekeeping** **list** [*-n*] [*-o FORMAT*]
+| **flux** **housekeeping** **kill** [*--all*] [*-j JOBID*] [*-t HOSTS|RANKS*] [*-s SIGNUM*]
+
+
+DESCRIPTION
+===========
+
+.. program:: flux housekeeping
+
+The housekeeping service provides similar functionality to
+a job epilog, with a few advantages
+
+ - Housekeeping runs after the job, which is then allowed to exit CLEANUP
+ state and become inactive once resources are released.
+ - While housekeeping is running, the scheduler still thinks resources are
+ allocated to the job, and will not allocate resources to other jobs.
+ - Housekeeping supports partial release of resources back to the scheduler,
+ such that a subset of stuck nodes do not hold up other nodes from
+ being returned to service.
+
+The :program:`flux housekeeping` command is used to interact with the
+housekeeping service. It supports listing the resources currently executing
+housekeeping actions and a command to forcibly terminate actions on a per-job
+or per-node basis.
+
+In a Flux system instance, housekeeping is configured by default to run as a
+one-shot :linux:man5:`systemd.unit`. See :ref:`troubleshooting` below.
+
+COMMANDS
+========
+
+list
+----
+
+.. program:: flux housekeeping list
+
+:program:`flux housekeeping list` lists active housekeeping tasks by jobid.
+
+.. option:: -i, --include=TARGETS
+
+ Filter results to only include resources matching *TARGETS*, which may
+ be specified either as an idset of broker ranks or a list of hosts in
+ hostlist form. It is not an error to specify ranks or hosts that do not
+ exist.
+
+.. option:: -o, --format=FORMAT
+
+ Customize the output format (See the `OUTPUT FORMAT`_ section below).
+
+.. option:: -n, --no-header
+
+ Suppress header from output.
+
+kill
+----
+
+.. program:: flux housekeeping kill
+
+:program:`flux housekeeping kill` can be used to terminate active housekeeping
+tasks. Housekeeping may be terminated by jobid, a set of targets such as
+broker ranks or hostnames, or all housekeeping may be terminated via the
+:option:`--all` option.
+
+.. option:: -s, --signal=SIGNUM
+
+ Send signal SIGNUM instead of SIGTERM.
+
+.. option:: -t, --targets=RANK|HOSTS
+
+ Target a specific set of ranks or hosts.
+
+.. option:: -j, --jobid=JOBID
+
+ Target a specific job by JOBID. Without ``--targets`` this will kill all
+ housekeeping tasks for the specified job.
+
+.. option:: --all
+
+ Target all housekeeping tasks for all jobs.
+
+OUTPUT FORMAT
+=============
+
+The :option:`--format` option can be used to specify an output format using
+Python's string format syntax or a defined format by name. For a list of
+built-in and configured formats use :option:`-o help`.
+
+The following field names can be specified for
+:command:`flux housekeeping list`:
+
+**id**
+ The jobid that triggered housekeeping
+
+**runtime**
+ The time since this housekeeping task started
+
+**nnodes**
+ A synonym for **allocated.nnodes**
+
+**ranks**
+ A synonym for **allocated.ranks**
+
+**nodelist**
+ A synonym for **allocated.nodelist**
+
+**allocated.nnodes**
+ The number of nodes still allocated to this housekeeping task.
+
+**allocated.ranks**
+ The list of broker ranks still allocated to this housekeeping task.
+
+**allocated.ranks**
+ The list of nodes still allocated to this housekeeping task.
+
+**pending.nnodes**
+ The number of nodes that still need to complete housekeeping.
+
+**pending.ranks**
+ The list of broker ranks that still need to complete housekeeping.
+
+**pending.ranks**
+ The list of nodes that still need to complete housekeeping.
+
+.. _troubleshooting:
+
+TROUBLESHOOTING
+===============
+
+In a Flux system instance, housekeeping is configured by default to run as a
+:linux:man5:`systemd.unit` named ``flux-housekeeping@JOBID``.
+
+:linux:man1:`systemctl` can show the status of housekeeping units running
+on the local node::
+
+ $ systemctl status flux-housekeeping@*
+
+:linux:man1:`journalctl` shows standard output and error of a housekeeping
+run::
+
+ $ journalctl -u flux-housekeeping@f4aTGTz2SN3
+
+When housekeeping fails, the systemd unit script drains the failing nodes
+with the reason obtained from systemd. For example, housekeeping runs
+that failed due to a nonzero exit code are distinguished from those that
+were aborted early due to a signal. In addition, a failure message is
+logged to Flux and can be accessed with :man1:`flux-dmesg`.
+
+When housekeeping hangs, no automated action is taken by Flux. Sending
+housekeeping a signal with :program:`flux housekeeping kill` causes
+:program:`systemctl stop` to be run on the housekeeping unit. Generally,
+it is best to let systemd take over from there. Its default action is to
+send SIGTERM to all processes in the control group, then SIGKILL if any
+processes have not terminated after a 90s delay.
+
+.. note::
+
+ On systems with scheduler configurations that permit jobs to share nodes,
+ multiple housekeeping units may execute concurrently on a single node.
+ Housekeeping scripts must be crafted with that in mind on such systems.
+
+CAVEATS
+=======
+
+The ``flux-housekeeping@`` systemd unit is responsible for draining nodes
+when housekeeping fails. Therefore if the system is configured to bypass
+the systemd unit file, or if housekeeping is misconfigured such that the
+the systemd unit file is not started, this draining does not occur.
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+SEE ALSO
+========
+
+:man5:`flux-config-job-manager`
diff --git a/doc/man1/flux-hwloc.adoc b/doc/man1/flux-hwloc.adoc
deleted file mode 100644
index dcc57a2f2b16..000000000000
--- a/doc/man1/flux-hwloc.adoc
+++ /dev/null
@@ -1,84 +0,0 @@
-// flux-help-command: hwloc
-// flux-help-description: Control/query resource-hwloc service
-FLUX-HWLOC(1)
-=============
-:doctype: manpage
-
-
-NAME
-----
-flux-hwloc - Control/query resource-hwloc service
-
-
-SYNOPSIS
---------
-*flux* *hwloc* *info* ['OPTIONS']
-
-*flux* *hwloc* *lstopo* ['lstopo-OPTIONS']
-
-*flux* *hwloc* *reload* ['OPTIONS'] ['DIR']
-
-*flux* *hwloc* *topology* ['OPTIONS']
-
-
-DESCRIPTION
------------
-The *flux-hwloc* utility provides a mechanism to collect
-system topology from each flux-broker using the Portable Hardware
-Locality (hwloc) library, and to query the resulting data
-stored in the Flux Key Value Store (KVS).
-
-COMMANDS
---------
-
-*flux hwloc* requires a 'COMMAND' argument. The supported commands
-are
-
-*info* ['-l,--local'|'-r,--rank=NODESET']::
-Dump a short-form summary of the total number of Machines, Cores,
-and Processing Units (PUs) available across all flux-brokers
-in the current instance. With '--ranks', dump information for
-only the specified ranks. With '--local' dump local system information.
-
-*lstopo*::
-Run `lstopo(1)` against the full hardware hierarchy configured in the
-current Flux instance. Extra `OPTIONS` are passed along to the system
-`lstopo(1)`. +
-By default, *flux hwloc lstopo* generates console output.
-For graphical output, try: *flux hwloc lstopo --of graphical*.
-
-*reload* ['-r,--rank=NODESET'] ['-v,--verbose] ['DIR']::
-Reload hwloc topology information, optionally loading hwloc XML files
-from `DIR/.xml` files. With '--rank' only reload XML on specified
-ranks. With '--verbose' this command runs with extra debugging and
-timing information.
-
-*topology* ['-l,--local'|'-r,--rank=NODESET']::
-Dump current aggregate topology XML for the current session to stdout.
-With '--rank' only dump aggregate topology for specified ranks. With
-'--local' dump topology XML for the local system.
-
-
-NODESET FORMAT
---------------
-include::NODESET.adoc[]
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-lstopo(1), hwloc: https://www.open-mpi.org/projects/hwloc/
diff --git a/doc/man1/flux-job.rst b/doc/man1/flux-job.rst
new file mode 100644
index 000000000000..693c2c7d0423
--- /dev/null
+++ b/doc/man1/flux-job.rst
@@ -0,0 +1,511 @@
+.. flux-help-description: get job status, info, etc (see: flux help job)
+.. flux-help-section: jobs
+
+===========
+flux-job(1)
+===========
+
+
+SYNOPSIS
+========
+
+| **flux** **job** **attach** [*--label-io*] [*-E*] [*--wait-event=EVENT*] *id*
+| **flux** **job** **status** [*-v*] [*--json*] [-e CODE] *id [*id...*]
+| **flux** **job** **last** [*N* | *SLICE*]
+| **flux** **job** **urgency** [*-v*] *id* *N*
+| **flux** **job** **wait** [*-v*] [*--all*] [*id*]
+| **flux** **job** **kill** [*--signal=SIG*] *ids...*
+| **flux** **job** **killall** [*-f*] [*--user=USER*] [*--signal=SIG*]
+| **flux** **job** **raise** [*--severity=N*] [*--type=TYPE*] *ids...* [*--*] [*message...*]
+| **flux** **job** **raiseall** [*--severity=N*] [*--user=USER*] [*--states=STATES*] *type* [ [*--*] [*message...*]
+| **flux** **job** **taskmap** [*OPTIONS*] *id* | *taskmap*
+| **flux** **job** **timeleft** [*-H*] [*id*]
+| **flux** **job** **purge** [*-f*] [*--age-limit=FSD*] [*--num-limit=N*] [*ids...*]
+| **flux** **job** **info** [*--original*] [*--base*] *id* *key*
+| **flux** **job** **hostpids** [*OPTIONS*] *id*
+
+
+DESCRIPTION
+===========
+
+:program:`flux job` performs various job related housekeeping functions.
+
+
+OPTIONS
+=======
+
+.. program:: flux job
+
+.. option:: -h, --help
+
+ Display a list of :program:`flux job` sub-commands.
+
+
+COMMANDS
+========
+
+Several subcommands are available to perform various operations on jobs.
+
+attach
+------
+
+.. program:: flux job attach
+
+A job can be interactively attached to via :program:`flux job attach`. This is
+typically used to watch stdout/stderr while a job is running or after it has
+completed. It can also be used to feed stdin to a job.
+
+When :program:`flux job attach` is run interactively -- that is all of
+``stdout``, ``stderr`` and ``stdin`` are attached to a tty -- the command may
+display a status line while the job is pending, e.g
+
+::
+
+ flux-job: ÆJqUHUCzX9 waiting for resources 00:00:08
+
+This status line may be suppressed by setting
+:envvar:`FLUX_ATTACH_NONINTERACTIVE` in the environment.
+
+.. option:: -l, --label-io
+
+ Label output by rank
+
+.. option:: -u, --unbuffered
+
+ Do not buffer stdin. Note that when ``flux job attach`` is used in a
+ terminal, the terminal itself may line buffer stdin.
+
+.. option:: -i, --stdin-ranks=RANKS
+
+ Send stdin to only those ranks in the **RANKS** idset. The standard input
+ for tasks not in **RANKS** will be closed. The default is to broadcast
+ stdin to all ranks.
+
+.. option:: --read-only
+
+ Operate in read-only mode. Disable reading of stdin and capturing of
+ signals.
+
+.. option:: -v, --verbose
+
+ Increase verbosity.
+
+.. option:: -w, --wait-event=EVENT
+
+ Wait for event *EVENT* before detaching from eventlog. The default is
+ ``finish``.
+
+.. option:: -E, --show-events
+
+ Show job events on stderr. This option also suppresses the status line
+ if enabled.
+
+.. option:: -X, --show-exec
+
+ Show exec eventlog events on stderr.
+
+.. option:: --show-status
+
+ Force immediate display of the status line.
+
+.. option:: --debug
+
+ Enable parallel debugger attach.
+
+status
+------
+
+.. program:: flux job status
+
+Wait for job(s) to complete and exit with the largest exit code.
+
+.. option:: -e, --exception-exit-code=N
+
+ Set the exit code for any jobs that terminate with an exception
+ (e.g. canceled jobs) to ``N``.
+
+.. option:: -j, --json
+
+ Dump job result information from job eventlog.
+
+.. option:: -v, --verbose
+
+ Increase verbosity of output.
+
+last
+-----
+
+.. program:: flux job last
+
+Print the most recently submitted jobid for the current user.
+
+If the optional argument is specified as a number *N*, print the *N* most
+recently submitted jobids in reverse submission order, one per line. If it
+is enclosed in brackets, the argument is interpreted as a `python-style slice
+`_
+in :option:`[start:stop[:step]]` form which slices the job history array,
+where index 0 is the most recently submitted job.
+
+Examples:
+
+:command:`flux job last 4`
+ List the last four jobids in reverse submission order
+
+:command:`flux job last [0:4]`
+ Same as above
+
+:command:`flux job last [-1:]`
+ List the least recently submitted jobid
+
+:command:`flux job last [:]`
+ List all jobids in reverse submission order
+
+:command:`flux job last [::-1]`
+ List all jobids in submission order
+
+urgency
+-------
+
+.. program:: flux job wait
+
+:program:`flux job urgency` changes a job's urgency value. The urgency
+may also be specified at job submission time. The argument *N* has a range
+of 0 to 16 for guest users, or 0 to 31 for instance owners. In lieu of a
+numerical value, the following special names are also accepted:
+
+hold (0)
+ Hold the job until the urgency is raised with :option:`flux job urgency`.
+
+default (16)
+ The default urgency for all users.
+
+expedite (31)
+ Assign the highest possible priority to the job (restricted to instance
+ owner).
+
+Urgency is one factor used to calculate job priority, which affects the
+order in which the scheduler considers jobs. For more information, refer
+to :man1:`flux-submit` description of the :option:`flux submit --urgency`
+option.
+
+wait
+----
+
+.. program:: flux job wait
+
+:program:`flux job wait` behaves like the UNIX :linux:man2:`wait` system call,
+for jobs submitted with the ``waitable`` flag. Compared to other methods
+of synchronizing on job completion and obtaining results, it is very
+lightweight.
+
+The result of a waitable job may only be consumed once. This is a design
+feature that makes it possible to call :program:`flux job wait` in a loop
+until all results are consumed.
+
+.. note::
+ Only the instance owner is permitted to submit jobs with the ``waitable``
+ flag.
+
+When run with a jobid argument, :program:`flux job wait` blocks until the
+specified job completes. If the job was successful, it silently exits with a
+code of zero. If the job has failed, an error is printed on stderr, and it
+exits with a code of one. If the jobid is invalid or the job is not waitable,
+:program:`flux job wait` exits with a code of two. This special exit code of
+two is used to differentiate between a failed job and not being able to wait
+on the job.
+
+When run without arguments, :program:`flux job wait` blocks until the next
+waitable job completes and behaves as above except that the jobid is printed
+to stdout. When there are no more waitable jobs, it exits with a code of two.
+The exit code of two can be used to determine when no more jobs are waitable
+when using :program:`flux job wait` in a loop.
+
+:option:`flux job wait --all` loops through all the waitable jobs as they
+complete, printing their jobids. If all jobs are successful, it exits with a
+code of zero. If any jobs have failed, it exits with a code of one.
+
+.. option:: -a, --all
+
+ Wait for all waitable jobs and exit with error if any jobs are
+ not successful.
+
+.. option:: -v, --verbose
+
+ Emit a line of output for all jobs, not just failing ones.
+
+kill
+----
+
+.. program:: flux job kill
+
+One or more running jobs may be signaled by jobid with :program:`flux job kill`.
+
+.. option:: -s, --signal=SIG
+
+ Send signal SIG (default: SIGTERM).
+
+killall
+-------
+
+.. program:: flux job killall
+
+Running jobs may be signaled in bulk with :program:`flux job killall`.
+
+.. option:: -u, --user=USER
+
+ Set target user. The instance owner may specify *all* for all users.
+
+.. option:: -f, --force
+
+ Confirm the command.
+
+.. option:: -s, --signal=SIG
+
+ Send signal SIG (default: SIGTERM).
+
+raise
+-----
+
+.. program:: flux job raise
+
+An exception may raised on one or more jobids with :program:`flux job raise`.
+An optional message included with the job exception may be provided via
+the :option:`--message=NOTE` option or after the list of jobids. The special
+argument *"--"* forces the end of jobid processing and can be used to
+separate the exception message from the jobids when necessary.
+
+.. option:: -m, --message=NOTE
+
+ Set the optional exception note. It is an error to specify the message
+ via this option and on the command line after the jobid list.
+
+.. option:: -s, --severity=N
+
+ Set exception severity. The severity may range from 0=fatal to
+ 7=least severe (default: 0).
+
+.. option:: -t, --type=TYPE
+
+ Set exception type (default: cancel).
+
+raiseall
+--------
+
+Exceptions may be raised in bulk with :program:`flux job raiseall`, which
+requires a type (positional argument) and accepts the following options:
+
+.. program:: flux job raiseall
+
+.. option:: -s, --severity=N
+
+ Set exception severity. The severity may range from 0=fatal to
+ 7=least severe (default: 7).
+
+.. option:: -u, --user=USER
+
+ Set target user. The instance owner may specify *all* for all users.
+
+.. option:: -S, --states=STATES
+
+ Set target job states (default: ACTIVE)
+
+.. option:: -f, --force
+
+ Confirm the command.
+
+taskmap
+-------
+
+.. program:: flux job taskmap
+
+The mapping between job task ranks to node IDs is encoded in the RFC 34
+Flux Task Map format and posted to the job's ``shell.start`` event in the
+exec eventlog. The :program:`flux job taskmap` utility is provided to assist in
+working with these task maps.
+
+When executed with a jobid argument and no options, the taskmap for the job
+is printed after the ``shell.start`` event has been posted.
+
+With one of the following arguments, the job taskmap may be used to convert
+a nodeid to a list of tasks, or to query on which node or host a given
+taskid ran. The command may also be used to convert between different
+support task mapping formats:
+
+.. option:: --taskids=NODEID
+
+ Print an idset of tasks which ran on node *NODEID*
+
+.. option:: --ntasks=NODEID
+
+ Print the number of tasks which ran on node *NODEID*
+
+.. option:: --nodeid=TASKID
+
+ Print the node ID that ran task *TASKID*
+
+.. option:: --hostname=TASKID
+
+ Print the hostname of the node that rank task *TASKID*
+
+.. option:: --to=raw|pmi|multiline|hosts
+
+ Convert the taskmap to *raw* or *pmi* formats (described in RFC 34),
+ *multiline* which prints the node ID of each task, one per line,
+ or *hosts* which prints a list of taskids for each host. The default
+ behavior is to print the RFC 34 taskmap. This option can be useful
+ to convert between mapping forms, since :program:`flux job taskmap`
+ can take a raw, pmi, or RFC 34 task map on the command line.
+
+Only one of the above options may be used per call.
+
+timeleft
+--------
+
+.. program:: flux job timeleft
+
+The :program:`flux job timeleft` utility reports the number of whole seconds
+left in the current or specified job time limit. If the job has expired or is
+complete, then this command reports ``0``. If the job does not have a time
+limit, then a large number (``UINT_MAX``) is reported.
+
+If :program:`flux job timeleft` is called outside the context of a Flux job, or
+an invalid or pending job is targeted, then this command will exit with
+an error and diagnostic message.
+
+Options:
+
+.. option:: -H, --human
+
+ Generate human readable output. Report results in Flux Standard Duration.
+
+purge
+-----
+
+.. program:: flux job purge
+
+Inactive job data may be purged from the Flux instance with
+:program:`flux job purge`. Specific job ids may be specified for purging.
+If no job ids are specified, the following options may be used for selection
+criteria:
+
+.. option:: --age-limit=FSD
+
+ Purge inactive jobs older than the specified Flux Standard Duration.
+
+.. option:: --num-limit=COUNT
+
+ Purge the oldest inactive jobs until there are at most COUNT left.
+
+.. option:: -f, --force
+
+ Confirm the command.
+
+Inactive jobs may also be purged automatically if the job manager is
+configured as described in :man5:`flux-config-job-manager`.
+
+
+info
+----
+
+.. program:: flux job info
+
+:program:`flux job info` retrieves the selected low level job object
+and displays it on standard output. Object formats are described in the
+RFCs listed in `RESOURCES`_.
+
+Options:
+
+.. option:: -o, --original
+
+ For :option:`jobspec`, return the original submitted jobspec, prior
+ to any modifications made at ingest, such as setting defaults.
+
+.. option:: -b, --base
+
+ For :option:`jobspec` or :option:`R`, return the base version, prior
+ to any updates posted to the job eventlog.
+
+The following keys are valid:
+
+eventlog
+ The primary job eventlog, consisting of timestamped events that drive the
+ job through various states. For example, a job that is pending resource
+ allocation in SCHED state transitions to RUN state on the *alloc* event.
+
+guest.exec.eventlog
+ The execution eventlog, consisting of timestamped events posted by the
+ execution system while the job is running.
+
+guest.input, guest.output
+ The job input and output eventlogs, consisting of timestamped chunks of
+ input/output data.
+
+jobspec
+ The job specification. Three versions are available:
+
+ - default: the *current* jobspec, which may reflect updates,
+ for example if the job duration was extended
+
+ - with :option:`--original`: the original jobspec submitted by the user
+
+ - with :option:`--base`: the jobspec as initially ingested to the KVS, after
+ the frobnicator filled in any default values, but before updates
+
+R
+ The resource set allocated to the job. Two versions are available:
+
+ - default: the *current* R, which may reflect updates, for example if the job
+ expiration time was extended (default)
+
+ - with :option:`--base`: the initial R allocated by the scheduler
+
+hostpids
+--------
+
+.. program:: flux job hostpids
+
+:program:`flux job hostpids` prints a comma-delimited list of
+``hostname:PID`` pairs for all tasks in a running job. If the job is
+pending, :program:`flux job hostpids` will block until all tasks in the
+job are running.
+
+Options:
+
+.. option:: -d, --delimiter=STRING
+
+ Set the output delimiter to STRING (default=``,``).
+
+.. option:: -r, --ranks=IDSET
+
+ Restrict output to the task ranks in IDSET. The default is to display
+ all ranks.
+
+.. option:: -t, --timeout=DURATION
+
+ Timeout the command after DURATION, which is specified in FSD.
+ (a floating point value with optional suffix ``s`` for seconds,
+ ``m`` for minutes, ``h`` for hours, or ``d`` for days).
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_14`
+
+:doc:`rfc:spec_18`
+
+:doc:`rfc:spec_20`
+
+:doc:`rfc:spec_21`
+
+:doc:`rfc:spec_24`
+
+:doc:`rfc:spec_25`
+
+:doc:`rfc:spec_34`
diff --git a/doc/man1/flux-jobs.adoc b/doc/man1/flux-jobs.adoc
deleted file mode 100644
index 9c8bdb09d628..000000000000
--- a/doc/man1/flux-jobs.adoc
+++ /dev/null
@@ -1,107 +0,0 @@
-// flux-help-include: true
-FLUX-JOBS(1)
-============
-:doctype: manpage
-
-
-NAME
-----
-flux-jobs - list jobs submitted to Flux
-
-
-SYNOPSIS
---------
-*flux* *jobs* ['OPTIONS']
-
-
-DESCRIPTION
------------
-flux-jobs(1) is used to list jobs run under Flux. By default only
-pending and running jobs for the current user are listed. Additional
-jobs and information can be listed using options listed below.
-
-
-OPTIONS
--------
-*-a*::
-List all jobs of the current user, including inactive jobs.
-Equivalent to specifying '--state=pending,running,inactive'.
-
-*-A*::
-List all jobs from all users, including inactive jobs. Equivalent to
-specifying '--state=pending,running,inactive --user=all'.
-
-*-n, --suppress-header*::
-For default output, do not output column headers.
-
-*-u, --user*'=[USERNAME|UID]'::
-List jobs for a specific username or userid. Specify 'all' for all users.
-
-*-c, --count*'=N'::
-Limit output to N jobs (default 1000)
-
-*-s, --states*'=STATES'::
-List jobs in specific job states or virtual job states. Multiple
-states can be listed separated by comma. See JOB STATES below for
-additional information. Defaults to 'pending,running'.
-
-*-o, --format*'=FORMAT'::
-Specify output format using Python's string format syntax. See OUTPUT
-FORMAT below for field names.
-
-JOB STATES
-----------
-Jobs may be observed to pass through five job states in Flux: DEPEND,
-SCHED, RUN, CLEANUP, and INACTIVE (see Flux RFC 21). For convenience
-and clarity, some options accept the following virtual job states:
-"pending", an alias for DEPEND,SCHED; "running", an alias for
-RUN,CLEANUP; "active", an alias for "pending,running".
-
-OUTPUT FORMAT
--------------
-
-The '--format' option can be used to specify an output format to
-flux-jobs(1) using Python's string format syntax. For example, the
-following is the format used for the default format:
-
- {id:>18} {username:<8.8} {name:<10.10} {state:<8.8} {ntasks:>6} {nnodes_hyphen:>6} {runtime_fsd_hyphen:>8} {ranks_hyphen}
-
-The field names that can be specified are:
-
-[horizontal]
-id:: job ID
-userid:: job submitter's userid
-username:: job submitter's username
-priority:: job priority
-state:: job state
-state_single:: job state as a single character
-name:: job name
-ntasks:: job task count
-nnodes:: job node count (if job ran / is running), empty string otherwise
-nnodes_hyphen:: same as nnodes, but '-' if job has not run yet / never ran
-ranks:: job ranks (if job ran / is running), empty string otherwise
-ranks_hyphen:: same as ranks, but '-' if job has not run yet / never ran
-t_submit:: time job was submitted
-t_depend:: time job entered depend state
-t_sched:: time job entered sched state
-t_run:: time job entered run state
-t_cleanup:: time job entered cleanup state
-t_inactive:: time job entered inactive state
-runtime:: job runtime
-runtime_fsd:: job runtime in Flux standard duration format
-runtime_fsd_hyphen:: same as runtime_fsd, but '-' if runtime is 0s
-runtime_hms:: job runtime in H:M:S format
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
diff --git a/doc/man1/flux-jobs.rst b/doc/man1/flux-jobs.rst
new file mode 100644
index 000000000000..cb614bd1cc28
--- /dev/null
+++ b/doc/man1/flux-jobs.rst
@@ -0,0 +1,674 @@
+.. flux-help-section: jobs
+
+============
+flux-jobs(1)
+============
+
+
+SYNOPSIS
+========
+
+**flux** **jobs** [*OPTIONS*] [JOBID ...]
+
+DESCRIPTION
+===========
+
+.. program:: flux jobs
+
+:program:`flux jobs` is used to list jobs run under Flux. By default only
+pending and running jobs for the current user are listed. Additional
+jobs and information can be listed using options listed below.
+Alternately, specific job ids can be listed on the command line to
+only list those job IDs.
+
+
+OPTIONS
+=======
+
+.. option:: -a
+
+ List jobs in all states, including inactive jobs.
+ This is shorthand for :option:`--filter=pending,running,inactive`.
+
+.. option:: -A
+
+ List jobs of all users. This is shorthand for :option:`--user=all`.
+
+.. option:: -n, --no-header
+
+ For default output, do not output column headers.
+
+.. option:: -u, --user=[USERNAME|UID]
+
+ List jobs for a specific username or userid. Specify *all* for all users.
+
+.. option:: --name=[JOB NAME]
+
+ List jobs with a specific job name.
+
+.. option:: -q, --queue=QUEUE[,...]
+
+ List jobs in a specific queue or queues. Multiple queues may be separated
+ by a comma or by using the :option:`-q, --queue` option multiple times.
+
+.. option:: -i, --include=HOSTS|RANKS
+
+ List only jobs where the assigned resources intersect with the supplied
+ argument, which may be specified either as an RFC 22 idset of broker ranks
+ or an RFC 29 hostlist of host names. It is not an error to specify ranks or
+ hosts which do not exist.
+
+.. option:: -c, --count=N
+
+ Limit output to N jobs. N=0 means unlimited. (default 1000)
+
+.. option:: --since=WHEN
+
+ Limit output to jobs that have been active since a given timestamp. In other
+ words, jobs that are currently pending, currently running, or became inactive
+ since the given timestamp. This option implies :option:`-a` if no other
+ :option:`--filter` options are specified. If *WHEN* begins with ``-``
+ character, then the remainder is considered to be a an offset in Flux
+ standard duration (RFC 23). Otherwise, any datetime expression accepted by
+ the Python `parsedatetime `_ module
+ is accepted. Examples: "-6h", "-1d", "yesterday", "2021-06-21 6am",
+ "last Monday", etc. It is assumed to be an error if a timestamp in
+ the future is supplied.
+
+ .. note::
+ Due to a quirk in the Python argument parsing implementation,
+ it is suggested to always use ``=`` between the :option:`--since`
+ option and its argument, e.g. ``--since=-1d`` rather than ``--since
+ -1d``. In the second case Python mistakenly considers the option
+ argument an unknown option and will raise an error about a missing
+ argument to :option:`--since`.
+
+
+.. option:: -f, --filter=STATE|RESULT
+
+ List jobs with specific job state or result. Multiple states or
+ results can be listed separated by comma. See `JOB STATUS`_ below for
+ additional information. Defaults to *pending,running*.
+
+.. option:: -o, --format=NAME|FORMAT
+
+ Specify a named output format *NAME* or a format string using Python's
+ format syntax. See `OUTPUT FORMAT`_ below for field names. Named formats
+ may be listed via :option:`--format=help`. An alternate default format can
+ be set via the :envvar:`FLUX_JOBS_FORMAT_DEFAULT` environment variable.
+ Additional named formats may be registered with :program:`flux jobs` via
+ configuration. See the `CONFIGURATION`_ section for more details. A
+ configuration snippet for an existing named format may be generated with
+ :option:`--format=get-config=NAME`.
+
+.. option:: --sort=[-]KEY,..
+
+ Sort jobs based on a list of comma separated keys. If a KEY is preceded
+ by a dash ``-``, then the sort order is reversed. Supported keys match
+ output field names, e.g. ``id``, ``t_run``, etc. This option overrides
+ any ``sort:`` prefix specified in the current format.
+
+.. option:: --json
+
+ Emit data for selected jobs in JSON format. The data for multiple
+ matching jobs is contained in a ``jobs`` array in the emitted JSON
+ object, unless a single job was selected by jobid on the command
+ line, in which case a JSON object representing that job is emitted on
+ success. With :option:`--recursive`, each job which is also an instance
+ of Flux will will have any recursively listed jobs in a ``jobs`` array,
+ and so on for each sub-child.
+
+ Only the attributes which are available at the time of the
+ :program:`flux jobs` query will be present in the returned JSON object for
+ a job. For instance a pending job will not have ``runtime``, ``waitstatus``
+ or ``result`` keys, among others. A missing key should be considered
+ unavailable.
+
+ The :option:`--json` option is incompatible with :option:`--stats` and
+ :option:`--stats-only`, and any :option:`--format` is ignored.
+
+.. option:: --color[=WHEN]
+
+ Control output coloring. The optional argument *WHEN* can be
+ *auto*, *never*, or *always*. If *WHEN* is omitted, it defaults to
+ *always*. Otherwise the default is *auto*.
+
+.. option:: --stats
+
+ Output a summary of job statistics before the header. By default
+ shows global statistics. If :option:`--queue` is specified, shows
+ statistics for the specified queue. May be useful in conjunction
+ with utilities like :linux:man1:`watch`, e.g.::
+
+ $ watch -n 2 flux jobs --stats -f running -c 25
+
+ will display a summary of statistics along with the top 25
+ running jobs, updated every 2 seconds.
+
+ Note that all job failures, including canceled and timeout jobs,
+ are collectively counted as "failed" in :option:`--stats`.
+
+.. option:: --stats-only
+
+ Output a summary of job statistics and exit. By default shows
+ global statistics. If :option:`--queue` is specified, shows statistics
+ for the specified queue. :program:`flux jobs` will exit with non-zero
+ exit status with :option:`--stats-only` if there are no active jobs. This
+ allows the following loop to work::
+
+ $ while flux jobs --stats-only; do sleep 2; done
+
+ All options other than :option:`--queue` are ignored when
+ :option:`--stats-only` is used.
+
+ Note that all job failures, including canceled and timeout jobs,
+ are collectively counted as "failed" in :option:`--stats-only`.
+
+.. option:: -R, --recursive
+
+ List jobs recursively. Each child job which is also an instance of
+ Flux is prefixed by its jobid "path" followed by the list of jobs,
+ recursively up to any defined :option:`--level`. If the :option:`--stats`
+ option is used, then each child instance in the hierarchy is listed
+ with its stats.
+
+.. option:: --recurse-all
+
+ By default, jobs not owned by the user running :program:`flux jobs` are
+ skipped with :option:`--recursive`, because normally Flux instances
+ only permit the instance owner to connect. This option forces the
+ command to attempt to recurse into the jobs of other users. Implies
+ :option:`--recursive`.
+
+.. option:: -L, --level=N
+
+ With :option:`--recursive`, stop recursive job listing at level **N**.
+ Levels are counted starting at 0, so :option:`flux jobs -R --level=0` is
+ equivalent to :program:`flux jobs` without :option:`-R`, and
+ :option:`--level=1` would limit recursive job listing to child jobs of the
+ current instance.
+
+.. option:: --threads=N
+
+ When :program:`flux jobs` recursively queries job lists (with
+ :option:`--recursive`) or fetches info for jobs that are also instances
+ (see ``instance.*`` fields), a pool of threads is used to parallelize
+ the required RPCs. Normally, the default number of ThreadPoolExecutor
+ threads is used, but by using the :option:`--threads`, a specific number
+ of threads can be chosen.
+
+.. _flux_jobs_job_status:
+
+JOB STATUS
+==========
+
+Jobs may be observed to pass through five job states in Flux: DEPEND,
+PRIORITY, SCHED, RUN, CLEANUP, and INACTIVE (see Flux RFC 21). Under the
+*state_single* field name, these are abbreviated as D, S, P, R, C, and I
+respectively. For convenience and clarity, the following virtual job
+states also exist: "pending", an alias for DEPEND,PRIORITY,SCHED; "running",
+an alias for RUN,CLEANUP; "active", an alias for "pending,running".
+
+After a job has finished and is in the INACTIVE state, it can be
+marked with one of the possible results: COMPLETED, FAILED,
+CANCELED, TIMEOUT. Under the *result_abbrev* field name, these are
+abbreviated as CD, F, CA, and TO respectively.
+
+The job status is a user friendly mix of both, a job is always in one
+of the following statuses: DEPEND, PRIORITY, SCHED, RUN, CLEANUP, COMPLETED,
+FAILED, CANCELED, or TIMEOUT. Under the *status_abbrev* field name,
+these are abbreviated as D, P, S, R, C, CD, F, CA, and TO respectively.
+
+
+.. _flux_jobs_output_format:
+
+OUTPUT FORMAT
+=============
+
+The :option:`--format` option can be used to specify an output format to
+:program:`flux jobs` using Python's string format syntax. For example, the
+following is the format used for the default format:
+
+::
+
+ {id.f58:>12} ?:{queue:<8.8} {username:<8.8} {name:<10.10+} \
+ {status_abbrev:>2.2} {ntasks:>6} {nnodes:>6h} \
+ {contextual_time!F:>8h} {contextual_info}
+
+If the format string begins with ``sort:k1[,k2,...]``, then ``k1[,k2,...]``
+will be taken to be a comma-separated list of keys on which to sort
+the displayed output. If a sort key starts with ``-``, then the key
+will be sorted in reverse order. The sort order embedded in the format
+ may be overridden on the command line by the :option:`--sort` option.
+
+If a format field is preceded by the special string ``?:`` this will
+cause the field to be removed entirely from output if the result would
+be an empty string or zero value for all jobs in the listing. E.g.::
+
+ {id.f58:>12} ?:{exception.type}
+
+would eliminate the EXCEPTION-TYPE column if no jobs in the list received
+an exception. (Thus the job queue is only displayed if at least one job
+has a queue assigned in the default format shown above).
+
+If a format field is preceded by the special string ``+:`` this will
+cause the field width to be set to the maximum width such that no entry
+will be truncated. If the field already has a width, then this will be
+the minimum width of that field. For example::
+
+ {id.f58:>12} +:{queue:>5}
+
+would set the width of the ``QUEUE`` field to the maximum of 5 and the
+actual width of the largest presented queue.
+
+If a format field is preceded by the string ``?+:``, then the field is
+eliminated if empty, or set the maximum item width.
+
+As a reminder to the reader, some shells will interpret braces
+(``{`` and ``}``) in the format string. They may need to be quoted.
+
+The special presentation type *h* can be used to convert an empty
+string, "0s", "0.0", "0:00:00", or epoch time to a hyphen. For example, normally
+"{nodelist}" would output an empty string if the job has not yet run.
+By specifying, "{nodelist:h}", a hyphen would be presented instead.
+
+The special suffix *+* can be used to indicate if a string was truncated
+by including a ``+`` character when truncation occurs. If both *h* and
+*+* are being used, then the *+* must appear after the *h*.
+
+Additionally, the custom job formatter supports a set of special
+conversion flags. Conversion flags follow the format field and are
+used to transform the value before formatting takes place. Currently,
+the following conversion flags are supported by :program:`flux jobs`:
+
+**!D**
+ convert a timestamp field to ISO8601 date and time (e.g. 2020-01-07T13:31:00).
+ Defaults to empty string if timestamp field does not exist or the timestamp
+ is 0 (i.e epoch time).
+
+**!d**
+ convert a timestamp to a Python datetime object. This allows datetime
+ specific format to be used, e.g. *{t_inactive!d:%H:%M:%S}*. Additionally,
+ width and alignment can be specified after the time format by using
+ two colons (``::``), e.g. *{t_inactive!d:%H:%M:%S::>20}*. Returns an
+ empty string (or "-" if the *h* suffix is used) for an unset timestamp.
+
+**!F**
+ convert a time duration in floating point seconds to Flux Standard
+ Duration (FSD) string (e.g. *{runtime!F}*). Defaults to empty string if
+ field does not exist.
+
+**!H**
+ convert a time duration in floating point seconds to
+ hours:minutes:seconds form (e.g. *{runtime!H}*). Defaults to empty
+ string if time duration field does not exist.
+
+**!P**
+ convert a floating point number into a percentage fitting in 5 characters
+ including the "%" character. E.g. 0.5 becomes "50%" 0.015 becomes 1.5%,
+ and 0.0005 becomes 0.05% etc.
+
+As a reminder to the reader, some shells will interpret the exclamation
+point (``!``) when using a conversion flag. The exclamation point may
+need to be escaped (``\!``).
+
+Annotations can be retrieved via the *annotations* field name.
+Specific keys and sub-object keys can be retrieved separated by a
+period ("."). For example, if the scheduler has annotated the job
+with a reason pending status, it can be retrieved via
+"{annotations.sched.reason_pending}".
+
+As a convenience, the field names *sched* and *user* can be used as
+substitutions for *annotations.sched* and *annotations.user*. For
+example, a reason pending status can be retrieved via
+"{sched.reason_pending}".
+
+The field names that can be specified are:
+
+**id**
+ job ID
+
+**id.f58**
+ job ID in RFC 19 F58 (base58) encoding
+
+**id.f58plain**
+ job ID in RFC 19 F58 encoding with ascii ``f``
+
+**id.dec**
+ job ID in decimal representation
+
+**id.hex**
+ job ID in ``0x`` prefix hexadecimal representation
+
+**id.dothex**
+ job ID in dotted hexadecimal representation (``xx.xx.xx.xx``)
+
+**id.words**
+ job ID in mnemonic encoding
+
+**id.emoji**
+ job ID in emoji encoding
+
+**userid**
+ job submitter's userid
+
+**username**
+ job submitter's username
+
+**urgency**
+ job urgency
+
+**priority**
+ job priority
+
+**dependencies**
+ list of any currently outstanding job dependencies
+
+**status**
+ job status (DEPEND, SCHED, RUN, CLEANUP, COMPLETED, FAILED,
+ CANCELED, or TIMEOUT)
+
+**status_abbrev**
+ status but in a max 2 character abbreviation
+
+**status_emoji**
+ status but an appropriate emoji instead of job state / result
+
+**name**
+ job name
+
+**cwd**
+ job current working directory
+
+**queue**
+ job queue
+
+**project**
+ job accounting project
+
+**bank**
+ job accounting bank
+
+**ntasks**
+ job task count
+
+**ncores**
+ job core count
+
+**duration**
+ job duration in seconds
+
+**nnodes**
+ job node count (if job ran / is running), empty string otherwise
+
+**ranks**
+ job ranks (if job ran / is running), empty string otherwise
+
+**nodelist**
+ job nodelist (if job ran / is running), empty string otherwise
+
+**state**
+ job state (DEPEND, SCHED, RUN, CLEANUP, INACTIVE)
+
+**state_single**
+ job state as a single character
+
+**state_emoji**
+ job state but an appropriate emoji instead of DEPEND, SCHED, RUN,
+ CLEANUP, or INACTIVE
+
+**result**
+ job result if job is inactive (COMPLETED, FAILED, CANCELED, TIMEOUT),
+ empty string otherwise
+
+**result_abbrev**
+ result but in a max 2 character abbreviation
+
+**result_emoji**
+ result but an appropriate emoji instead of COMPLETED, FAILED,
+ CANCELED, or TIMEOUT
+
+**success**
+ True of False if job completed successfully, empty string otherwise
+
+**waitstatus**
+ The raw status of the job as returned by :linux:man2:`waitpid` if the job
+ exited, otherwise an empty string. Note: *waitstatus* is the maximum
+ wait status returned by all job shells in a job, which may not necessarily
+ indicate the highest *task* wait status. (The job shell exits with the
+ maximum task exit status, unless a task died due to a signal, in which
+ case the shell exits with 128+signo)
+
+**returncode**
+ The job return code if the job has exited, or an empty string if the
+ job is still active. The return code of a job is the highest job shell
+ exit code, or negative signal number if the job shell was terminated by
+ a signal. If the job was canceled before it started, then the returncode
+ is set to the special value -128.
+
+**exception.occurred**
+ True of False if job had an exception, empty string otherwise
+
+**exception.severity**
+ If exception.occurred True, the highest severity, empty string otherwise
+
+**exception.type**
+ If exception.occurred True, the highest severity exception type, empty string otherwise
+
+**exception.note**
+ If exception.occurred True, the highest severity exception note, empty string otherwise
+
+**t_submit**
+ time job was submitted
+
+**t_depend**
+ time job entered depend state
+
+**t_run**
+ time job entered run state
+
+**t_cleanup**
+ time job entered cleanup state
+
+**t_inactive**
+ time job entered inactive state
+
+**runtime**
+ job runtime
+
+**expiration**
+ time at which job allocation was marked to expire
+
+**t_remaining**
+ If job is running, amount of time remaining before expiration
+
+**annotations**
+ annotations metadata, use "." to get specific keys
+
+**sched**
+ short hand for *annotations.sched*
+
+**user**
+ short hand for *annotations.user*
+
+
+Field names which are specific to jobs which are also instances of Flux
+include:
+
+**instance.stats**
+ a short string describing current job statistics for the instance of
+ the form ``PD:{pending} R:{running} CD:{successful} F:{failed}``
+
+**instance.stats.total**
+ total number of jobs in any state in the instance.
+
+**instance.utilization**
+ number of cores currently allocated divided by the total number of cores.
+ Can be formatted as a percentage with ``!P``, e.g.
+ ``{instance.utilization!P:>4}``.
+
+**instance.gpu_utilization**
+ same as ``instance.utilization`` but for gpu resources
+
+**instance.progress**
+ number of inactive jobs divided by the total number of jobs.
+ Can be formatted as a percentage with ``{instance.progress!P:>4}``
+
+**instance.resources..{ncores,ngpus}**
+ number of cores, gpus in state ``state``, where ``state`` can be
+ ``all``, ``up``, ``down``, ``allocated``, or ``free``, e.g.
+ ``{instance.resources.all.ncores}``
+
+The following fields may return different information depending on
+the state of the job or other context:
+
+**contextual_info**
+ Returns selected information based on the job's current state. If the
+ job is in PRIORITY state, then the string ``priority-wait`` is returned.
+ If the job is in DEPEND state, then a list of outstanding dependencies
+ is returned. If the job is in SCHED state and its priority is currently
+ 0, then one of ``held`` or ``priority-hold`` will be printed depending
+ on if urgency is also 0, otherwise an estimated time the job will run is
+ returned (if supported by the scheduler). In other states, the assigned
+ nodelist is returned (if resources were assigned).
+
+**contextual_info**
+ Returns the job runtime for jobs in RUN state or later, otherwise the
+ job duration (if set) is returned.
+
+**inactive_reason**
+ If the job is inactive, returns the reason that the job is no
+ longer active. Generally speaking, will output "Exit", "Timeout",
+ "Canceled", or signal. If available, other contextual information
+ will also be provided such as the exit ``returncode`` or
+ cancellation message.
+
+.. _flux_jobs_configuration:
+
+CONFIGURATION
+=============
+
+The :program:`flux jobs` command supports registration of named output formats
+in configuration files. The command loads configuration files from
+``flux-jobs.EXT`` from the following paths in order of increasing precedence:
+
+ * ``$XDG_CONFIG_DIRS/flux`` or ``/etc/xdg/flux`` if :envvar:`XDG_CONFIG_DIRS`
+ is not set. Note that :envvar:`XDG_CONFIG_DIRS` is traversed in reverse
+ order such that entries first in the colon separated path are highest
+ priority.
+
+ * ``$XDG_CONFIG_HOME/flux`` or ``$HOME/.config/flux`` if
+ :envvar:`XDG_CONFIG_HOME` is not set
+
+where ``EXT`` can be one of ``toml``, ``yaml``, or ``json``.
+
+If there are multiple ``flux-jobs.*`` files found in a directory, then
+they are loaded in lexical order (i.e. ``.json`` first, then ``.toml``,
+then ``.yaml``)
+
+Named formats are registered in a ``formats`` table or dictionary with a
+key per format pointing to a table or dictionary with the keys:
+
+**format**
+ (required) The format string
+
+**description**
+ (optional) A short description of the named format, displayed with
+ :option:`flux jobs --format=help`
+
+If a format name is specified in more than one config file, then the last
+one loaded is used. Due to the order that :program:`flux jobs` loads config
+files, this allows user configuration to override system configuration. It is
+an error to override any internally defined formats (such as ``default``).
+
+If a format name or string is not specified on the command line the
+internally defined format ``default`` is used.
+
+Example::
+
+ # $HOME/.config/flux/flux-jobs.toml
+
+ [formats.myformat]
+ description = "My useful format"
+ format = """\
+ {id.f58:>12} {name:>8.8} {t_submit!D:<19} \
+ {t_run!D:<19} {t_remaining!F}\
+ """
+
+It may be helpful to start with an existing named format by using the
+:option:`--format=get-config=NAME` option, e.g.::
+
+ $ flux jobs --format=get-config=default >> ~/.config/flux/flux-jobs.toml
+
+Be sure to change the name of the format string from ``default``. It is an
+error to redefine the default format string.
+
+
+EXAMPLES
+========
+
+The default output of :program:`flux jobs` will list the pending and running
+jobs of the current user. It is equivalent to:
+
+::
+
+ $ flux jobs --filter=pending,running
+
+To list all pending, running, and inactive jobs, of the current user,
+you can use :option:`--filter` option or the :option:`-a` option:
+
+::
+
+ $ flux jobs -a
+
+ OR
+
+ $ flux jobs --filter=pending,running,inactive
+
+To alter which user's jobs are listed, specify the user with :option:`--user`:
+
+::
+
+ $ flux jobs --user=flux
+
+Jobs that have finished may be filtered further by specifying if they
+have completed, failed, or were canceled. For example, the following
+will list the jobs that have failed or were canceled:
+
+::
+
+ $ flux jobs --filter=failed,canceled
+
+The :option:`--format` option can be used to alter the output format or output
+additional information. For example, the following would output all
+jobids for the user in decimal form, and output any annotations the
+scheduler attached to each job:
+
+::
+
+ $ flux jobs -a --format="{id} {annotations.sched}"
+
+The following would output the job id and exception information, so a
+user can learn why a job failed.
+
+::
+
+ $ flux jobs --filter=failed --format="{id} {exception.type} {exception.note}"
+
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+FLUX RFC
+========
+
+| :doc:`rfc:spec_22`
+| :doc:`rfc:spec_29`
+
+SEE ALSO
+========
+
+:man1:`flux-pstree`
diff --git a/doc/man1/flux-jobtap.rst b/doc/man1/flux-jobtap.rst
new file mode 100644
index 000000000000..a22df091cfd4
--- /dev/null
+++ b/doc/man1/flux-jobtap.rst
@@ -0,0 +1,79 @@
+==============
+flux-jobtap(1)
+==============
+
+
+SYNOPSIS
+========
+
+| **flux** **jobtap** **load** [*--remove=NAME*] *plugin* [*key=val...*]
+| **flux** **jobtap** **remove** *plugin*
+| **flux** **jobtap** **list** [*--all*]
+| **flux** **jobtap** **query** *plugin*
+
+DESCRIPTION
+===========
+
+The :program:`flux jobtap` command is used to query, load, and remove *jobtap*
+plugins from the Flux job-manager module at runtime.
+
+COMMANDS
+========
+
+load
+----
+
+.. program:: flux jobtap load
+
+Load a new plugin into the job-manager. Optional *key=val* arguments
+occurring after *plugin* will set config *key* to *val* for *plugin*.
+
+.. option:: --remove=NAME
+
+ Remove plugin *NAME* before loading *plugin*. *NAME* may be a
+ :linux:man7:`glob` pattern match.
+
+remove
+------
+
+.. program:: flux jobtap remove
+
+Remove *plugin*. *plugin* may be a :linux:man7:`glob` pattern in
+which case all matching, non-builtin plugins are removed. The
+special value ``all`` may be used to remove all loaded jobtap
+plugins. Builtin plugins (those starting with a leading ``.``) must
+be removed explicitly or by preceding *NAME* with ``.``,
+e.g. ``.*``.
+
+list
+----
+
+.. program:: flux jobtap list
+
+Print the currently loaded list of plugins. Plugins built in to the job
+manager have a leading ``.`` in the name, e.g. ``.priority-default``.
+They are not displayed by default.
+
+.. option:: -a, --all
+
+ List builtin plugins too.
+
+query
+-----
+
+.. program:: flux jobtap query
+
+Print a JSON object with extended information about *plugin*. This
+includes at least the plugin name and path (or "builtin" if the plugin
+was loaded internally), but may contain plugin-specific data if the plugin
+supports the ``plugin.query`` callback topic.
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+SEE ALSO
+========
+
+:man7:`flux-jobtap-plugins`
diff --git a/doc/man1/flux-keygen.adoc b/doc/man1/flux-keygen.adoc
deleted file mode 100644
index b15cfdf29f42..000000000000
--- a/doc/man1/flux-keygen.adoc
+++ /dev/null
@@ -1,77 +0,0 @@
-// flux-help-include: true
-FLUX-KEYGEN(1)
-==============
-:doctype: manpage
-
-
-NAME
-----
-flux-keygen - generate keys for Flux security
-
-
-SYNOPSIS
---------
-*flux* *keygen* ['--force'] ['--plain']
-
-
-DESCRIPTION
------------
-flux-keygen(1) generates long-term keys for Flux security.
-Keys are written to files in '$HOME/.flux'.
-
-Flux comms sessions implement cryptographic privacy and data integrity
-when data is sent over a network. Point to point ZeroMQ TCP connections
-are protected with the CURVE security mechanism built into ZeroMQ
-version 4, based on curve25519 and a CurveCP-like protocol.
-
-It is possible to start a Flux comms session with security
-disabled or using the toy PLAIN ZeroMQ security mechanism.
-This is intended for testing performance overhead of security only.
-By default, *flux-keygen* generates both CURVE and PLAIN keys.
-PLAIN keys are merely RFC 4122 uuids stored in the clear that are
-used as passwords.
-
-All instances of Flux message brokers launched in a comms session
-need to access your keys, therefore we assume that your '$HOME/.flux'
-directory is globally accessible. Of course if keys are being transferred
-in the clear across public networks to make this happen, you have
-the same sort of problem as you might have with ssh private keys stored
-in your home directory.
-
-The Flux security design is not yet complete, and these measures
-are probably not the final ones.
-
-OPTIONS
--------
-*-f, --force*::
-Generate new keys, even if they already exist.
-
-*-p, --plain*::
-Generate PLAIN key.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-ZAP:
-
-CurveZMQ:
-
-ZMTP/3.0:
-
-Using ZeroMQ Security:
- and
-
diff --git a/doc/man1/flux-keygen.rst b/doc/man1/flux-keygen.rst
new file mode 100644
index 000000000000..673531be37c2
--- /dev/null
+++ b/doc/man1/flux-keygen.rst
@@ -0,0 +1,62 @@
+==============
+flux-keygen(1)
+==============
+
+
+SYNOPSIS
+========
+
+**flux** **keygen** [*--name=NAME*] [*--meta=KEY=VAL...*] *PATH*
+
+
+DESCRIPTION
+===========
+
+.. program:: flux keygen
+
+:program:`flux keygen` generates a long-term CURVE certificate used to secure
+the overlay network of a Flux system instance.
+
+The Flux overlay network implements cryptographic privacy and data integrity
+when data is sent over a network. Point to point ZeroMQ TCP connections
+are protected with the CURVE security mechanism built into ZeroMQ
+version 4, based on curve25519 and a CurveCP-like protocol.
+
+All brokers participating in the system instance must use the same
+certificate. The certificate is part of the bootstrap configuration.
+
+Flux instances that bootstrap with PMI do not require a configured certificate.
+In that case, each broker self-generates a unique certificate and the
+public keys are exchanged with PMI.
+
+
+OPTIONS
+=======
+
+:program:`flux keygen` accepts the following options:
+
+.. option:: -n, --name=NAME
+
+ Set the certificate metadata ``name`` field. The value is logged when
+ :man1:`flux-broker` authenticates a peer that presents this certificate.
+ A cluster name might be appropriate here. Default: the local hostname.
+
+.. option:: --meta=KEY=VAL
+
+ Set arbitrary certificate metadata. Multiple key-value pairs may be
+ specified, separated by commas. This option may be specified multiple
+ times.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+ZAP: http://rfc.zeromq.org/spec:27
+
+CurveZMQ: http://curvezmq.org/page:read-the-docs
+
+ZMTP/3.0: http://rfc.zeromq.org/spec:23
+
+Using ZeroMQ Security: http://hintjens.com/blog:48, http://hintjens.com/blog:49
diff --git a/doc/man1/flux-kvs.adoc b/doc/man1/flux-kvs.adoc
deleted file mode 100644
index 8871bb3222c2..000000000000
--- a/doc/man1/flux-kvs.adoc
+++ /dev/null
@@ -1,208 +0,0 @@
-// flux-help-include: true
-FLUX-KVS(1)
-===========
-:doctype: manpage
-
-
-NAME
-----
-flux-kvs - Flux key-value store utility
-
-
-SYNOPSIS
---------
-*flux* *kvs* 'COMMAND' ['OPTIONS']
-
-
-DESCRIPTION
------------
-The Flux key-value store (KVS) is a simple, distributed data storage
-service used a building block by other Flux components.
-flux-kvs(1) is a command line utility that operates on the KVS.
-It is a very thin layer on top of a C API.
-
-The Flux KVS stores values under string keys. The keys are
-hierarchical, using "." as a path separator, analogous to "/"
-separated UNIX file paths. A single "." represents the root directory
-of the KVS.
-
-The KVS is distributed among the ranks of a comms session. Rank 0
-is the leader, and other ranks are caching followers. All writes are flushed
-to the leader during a commit operation. Data is stored in a hash tree
-such that every commit results in a new root hash. Each new root hash
-is multicast across the session. When followers update their root hash,
-they atomically update their view to match the leader. There may be a
-delay after a commit while old data is served on a follower that has not yet
-updated its root hash, thus the Flux KVS consistency model is "eventually
-consistent". Followers cache data temporally and fault in new data through
-their parent in the overlay network.
-
-Different KVS namespaces can be created in which kvs values can be
-read from/written to. By default, all KVS operations operate on the
-default KVS namespace "primary". An alternate namespace can be
-specified in most kvs commands via the '--namespace' option, or by
-setting the namespace in the environment variable FLUX_KVS_NAMESPACE.
-
-flux-kvs(1) runs a KVS 'COMMAND'. The possible commands and their
-arguments are described below.
-
-COMMANDS
---------
-*namespace create* [-o owner] 'name' ['name...']::
-Create a new kvs namespace. User may specify an alternate userid of a
-user that owns the namespace via '-o'. Specifying an alternate owner
-would allow a non-instance owner to read/write to a namespace.
-
-*namespace remove* 'name' ['name...']::
-Remove a kvs namespace.
-
-*namespace list*::
-List all current namespaces and info on each namespace.
-
-*get* [-N ns] [-r|-t] [-a treeobj] [-l] [-W] [-w] [-u] [-A] [-f] [-c count] 'key' ['key...']::
-Retrieve the value stored under 'key'. If nothing has been stored
-under 'key', display an error message. Specify an alternate namespace
-to retrieve 'key' from via '-N'. If no options, value is displayed
-with a newline appended (if value length is nonzero). If '-l', a
-'key=' prefix is added. If '-r', value is displayed without a newline.
-If '-t', the RFC 11 object is displayed. '-a treeobj' causes the
-lookup to be relative to an RFC 11 snapshot reference. If '-W' is
-specified and a key does not exist, wait until the key has been
-created. If '-w', after the initial value, display the new value each
-time the key is written to until interrupted, or if '-c count' is
-specified, until 'count' values have been displayed. If '-u' is
-specified, only writes that change the key value will be displayed.
-If '-A' is specified, only display appends that occur on a key. By
-default, only a direct write to a key is monitored, which may miss
-several unique situations, such as the replacement of an entire parent
-directory. The '-f' option can be specified to monitor for many of
-these special situations.
-
-*put* [-N ns] [-O|-s] [-r|-t] [-n] [-A] 'key=value' ['key=value...']::
-Store 'value' under 'key' and commit it. Specify an alternate
-namespace to commit value(s) via '-N'. If it already has a value,
-overwrite it. If no options, value is stored directly. If '-r' or
-'-t', the value may optionally be read from standard input if
-specified as "-". If '-r', the value may include embedded NULL bytes.
-If '-t', value is stored as a RFC 11 object. '-n' prevents the commit
-from being merged with with other contemporaneous commits. '-A'
-appends the value to a key instead of overwriting the value. Append
-is incompatible with the -j option. After a successful put, '-O' or
-'-s' can be specified to output the RFC11 treeobj or root sequence
-number of the root containing the put(s).
-
-*ls* [-N ns] [-R] [-d] [-F] [-w COLS] [-1] ['key' ...]::
-Display directory referred to by _key_, or "." (root) if unspecified.
-Specify an alternate namespace to display via '-N'. Remaining options are
-roughly equivalent to a subset of ls(1) options. '-R' lists directory
-recursively. '-d' displays directory not its contents. '-F'
-classifies files with one character suffix (. is directory, @ is
-symlink). '-w COLS' sets the terminal width in characters. '-1'
-causes output to be displayed in one column.
-
-*dir* [-N ns] [-R] [-d] [-w COLS] [-a treeobj] ['key']::
-Display all keys and their values under the directory 'key'. Specify
-an alternate namespace to display via '-N'. If 'key' does not exist
-or is not a directory, display an error message. If 'key' is not
-provided, "." (root of the namespace) is assumed. If '-R' is
-specified, recursively display keys under subdirectories. If '-d' is
-specified, do not output key values. Output is truncated to fit the
-terminal width. '-w COLS' sets the terminal width (0=unlimited). '-a
-treeobj' causes the lookup to be relative to an RFC 11 snapshot
-reference.
-
-*unlink* [-N ns] [-O|-s] [-R] [-f] 'key' ['key...']::
-Remove 'key' from the KVS and commit the change. Specify an alternate
-namespace to commit to via '-N'. If 'key' represents a directory,
-specify '-R' to remove all keys underneath it. If '-f' is specified,
-ignore nonexistent files. After a successful unlink, '-O' or '-s' can
-be specified to output the RFC11 treeobj or root sequence number of
-the root containing the unlink(s).
-
-*link* [-N ns] [-T ns] [-O|-s] 'target' 'linkname'::
-Create a new name for 'target', similar to a symbolic link, and commit
-the change. 'target' does not have to exist. If 'linkname' exists,
-it is overwritten. Specify an alternate namespace to commit linkname
-to via '-N'. Specify the target's namespace via '-T'. After a
-successfully created link, '-O' or '-s' can be specified to output the
-RFC11 treeobj or root sequence number of the root containing the link.
-
-*readlink* [-N ns] [-a treeobj] [ -o | -k ] 'key' ['key...']::
-Retrieve the key a link refers to rather than its value, as would be
-returned by *get*. Specify an alternate namespace to retrieve from
-via '-N'. '-a treeobj' causes the lookup to be relative to an RFC 11
-snapshot reference. If the link points to a namespace, the namespace
-and key will be output in the format '::'. The '-o'
-can be used to only output namespaces and the '-k' can be used to only
-output keys.
-
-*mkdir* [-N ns] [-O|-s] 'key' ['key...']::
-Create an empty directory and commit the change. If 'key' exists,
-it is overwritten. Specify an alternate namespace to commit to via
-'-N'. After a successful mkdir, '-O' or '-s' can be specified to
-output the RFC11 treeobj or root sequence number of the root
-containing the new directory.
-
-*copy* [-S src-ns] [-D dst-ns] 'source' 'destination'::
-Copy 'source' key to 'destination' key. Optionally, specify a source
-and/or destination namespace for the 'source' and/or 'destination'
-respectively. If a directory is copied, a new reference is created;
-it is unnecessary for *copy* to recurse into 'source'.
-
-*move* [-S src-ns] [-D dst-ns] 'source' 'destination'::
-Like *copy*, but 'source' is unlinked after the copy.
-
-*dropcache* [--all]::
-Tell the local KVS to drop any cache it is holding. If '--all' is
-specified, send an event across the comms session instructing all KVS
-instances to drop their caches.
-
-*version* [-N ns]::
-Display the current KVS version, an integer value. The version starts
-at zero and is incremented on each KVS commit. Note that some commits
-may be aggregated for performance and the version will be incremented
-once for the aggregation, so it cannot be used as a direct count of
-commit requests. Specify an alternate namespace to retrieve the
-version from via '-N'.
-
-*wait* [-N ns] 'version'::
-Block until the KVS version reaches 'version' or greater. A simple form
-of synchronization between peers is: node A puts a value, commits it,
-reads version, sends version to node B. Node B waits for version, gets
-value.
-
-*getroot* [-N ns] [-s | -o]::
-Retrieve the current KVS root, displaying it as an RFC 11 dirref object.
-Specify an alternate namespace to retrieve from via '-N'. If '-o' is
-specified, display the namespace owner. If '-s' is specified, display
-the root sequence number.
-
-*eventlog get* [-N ns] [-w] [-c count] [-u] 'key'::
-Display the contents of an RFC 18 KVS eventlog referred to by 'key'.
-If '-u' is specified, display the log in raw form. If '-w' is
-specified, after the existing contents have been displayed, the
-eventlog is monitored and updates are displayed as they are committed.
-This runs until the program is interrupted or an error occurs, unless
-the number of events is limited with the '-c' option. Specify an
-alternate namespace to display from via '-N'.
-
-*eventlog append* [-N ns] [-t SECONDS] 'key' 'name' ['context ...']::
-Append an event to an RFC 18 KVS eventlog referred to by 'key'.
-The event 'name' and optional 'context' are specified on the command line.
-The timestamp may optionally be specified with '-t' as decimal seconds since
-the UNIX epoch (UTC), otherwise the current wall clock is used.
-Specify an alternate namespace to append to via '-N'.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
diff --git a/doc/man1/flux-kvs.rst b/doc/man1/flux-kvs.rst
new file mode 100644
index 000000000000..e91975bdc7c2
--- /dev/null
+++ b/doc/man1/flux-kvs.rst
@@ -0,0 +1,574 @@
+===========
+flux-kvs(1)
+===========
+
+
+SYNOPSIS
+========
+
+| **flux** **kvs** **get** [*--waitcreate*] [*--watch*] [*--raw*] *key...*
+| **flux** **kvs** **put** [*--append*] [*--raw*] *key=value...*
+| **flux** **kvs** **dir** [*-R*] [*-d*] [*key*]
+| **flux** **kvs** **ls** [*-R*] [*-d*] [*-1*] [*-F*] *key...*
+| **flux** **kvs** **unlink** [*-R*] [*-f*] *key...*
+| **flux** **kvs** **link** *target* *linkname*
+| **flux** **kvs** **readlink** *key...*
+| **flux** **kvs** **mkdir** *key...*
+| **flux** **kvs** **dropcache**
+
+| **flux** **kvs** **copy** *source* *destination*
+| **flux** **kvs** **move** *source* *destination*
+
+| **flux** **kvs** **getroot**
+| **flux** **kvs** **version**
+| **flux** **kvs** **wait** *version*
+
+| **flux** **kvs** **namespace** **create** [*-o owner*] *name...*
+| **flux** **kvs** **namespace** **remove** *name...*
+| **flux** **kvs** **namespace** **list**
+
+| **flux** **kvs** **eventlog** **append** *key* *name* [*context...*]
+| **flux** **kvs** **eventlog** **get** [*--waitcreate*] [*--watch*] [*-u*] *key*
+| **flux** **kvs** **eventlog** **wait-event** [*-v*] [*--waitcreate*] *key* *event*
+
+
+DESCRIPTION
+===========
+
+The Flux key-value store (KVS) is a simple, distributed data storage
+service used a building block by other Flux components.
+:program:`flux kvs` is a command line utility that operates on the KVS.
+
+The Flux KVS stores values under string keys. The keys are
+hierarchical, using "." as a path separator, analogous to "/"
+separated UNIX file paths. A single "." represents the root directory
+of the KVS.
+
+The KVS is distributed among the broker ranks of a Flux instance. Rank 0
+is the leader, and other ranks are caching followers. All writes are flushed
+to the leader during a commit operation. Data is stored in a hash tree
+such that every commit results in a new root hash. Each new root hash
+is multicast across the Flux instance. When followers update their root hash,
+they atomically update their view to match the leader. There may be a
+delay after a commit while old data is served on a follower that has not yet
+updated its root hash, thus the Flux KVS cache is "eventually consistent".
+Followers expire cache data after a period of disuse, and fault in new data
+through their parent in the overlay network.
+
+The primary KVS namespace is only accessible to the Flux instance owner.
+Other namespaces may be created and assigned to guest users. Although the
+cache is shared across namespaces, each has an independent root directory,
+which permits commits in multiple namespaces to complete in parallel.
+
+
+COMMANDS
+========
+
+.. program:: flux kvs
+
+The :program:`flux kvs` sub-commands and their arguments are described below.
+
+The following options are common to most sub-commands:
+
+.. option:: -h, --help
+
+ Display help on this sub-command.
+
+.. option:: -N, --namespace=NAME
+
+ Specify an alternate namespace. By default, the primary KVS namespace
+ or the value of :envvar:`FLUX_KVS_NAMESPACE` is used.
+
+get
+---
+
+.. program:: flux kvs get
+
+Retrieve the value stored under *key* and print it on standard output.
+It is an error if *key* does not exist, unless :option:``--waitcreate`` is
+specified. It is an error if *key* is a directory.
+
+If multiple *key* arguments are specified, their values are concatenated.
+A newline is appended to each value, unless :option:`--raw` is specified or
+the value is zero length.
+
+.. option:: -r, --raw
+
+ Display value without a newline.
+
+.. option:: -t, --treeobj
+
+ Display RFC 11 tree object.
+
+.. option:: -a, --at=TREEOBJ
+
+ Perform the lookup relative to a directory reference in RFC 11 tree object
+ format.
+
+.. option:: -l, --label
+
+ Add *key=* prefix to output.
+
+.. option:: -W, --waitcreate
+
+ If the key does not exist, wait until it does, then return its value.
+
+.. option:: -w, --watch
+
+ Display the initial value for *key*, then watch for changes and display
+ each new value until interrupted or :option:`--count=N` is reached.
+
+.. option:: -c, --count=N
+
+ With :option:`--watch`, display *N* values then exit.
+
+.. option:: -u, --uniq
+
+ With :option:`--watch`, suppress output when value is the same, even
+ if the watched key was the target of a KVS commit.
+
+.. option:: -A, --append
+
+ With :option:`--watch`, display only the new data when the watched
+ value is appended to.
+
+.. option:: -f, --full
+
+ With :option:`--watch`, monitor key changes with more complete accuracy.
+
+ By default, only a direct write to a key is monitored, thus changes that
+ occur indirectly could be missed, such as when the parent directory is
+ replaced. The :option:`--full` option ensures these changes are reported
+ as well, at greater overhead.
+
+put
+---
+
+.. program:: flux kvs put
+
+Set *key* to *value*. If *key* exists, the current value is overwritten.
+If multiple *key=value* pairs are specified, they are sent as one
+commit and succeed or fail atomically.
+
+.. option:: -O, --treeobj-root
+
+ After the commit has completed, display the new root directory reference
+ in RFC 11 tree object format.
+
+.. option:: -b, --blobref
+
+ After the commit has completed, display the new root directory reference
+ as a single blobref.
+
+.. option:: -s, --sequence
+
+ After the commit has completed, display the new root sequence number
+ or "version".
+
+.. option:: -r, --raw
+
+ Store *value* as-is, without adding NUL termination.
+ If *value* is ``-``, read it from standard input.
+ *value* may include embedded NUL bytes.
+
+.. option:: -t, --treeobj
+
+ Interpret *value* as an RFC 11 tree object to be stored directly.
+ If *value* is ``-``, read it from standard input.
+
+.. option:: -n, --no-merge
+
+ Set the ``NO_MERGE`` flag on the commit to ensure it is not combined with
+ other commits. The KVS normally combines contemporaneous commits to save
+ work, but since commits succeed or fail atomically, this a commit could
+ fail due to collateral damage. This option prevents that from happening.
+
+.. option:: -A, --append
+
+ Append *value* to key's existing value, if any, instead of overwriting it.
+
+.. option:: -S, --sync
+
+ After the commit has completed, flush pending content and checkpoints
+ to disk. Commits normally complete with data in memory, which ensures a
+ subsequent :command:`flux kvs get` would receive the updated value, but
+ does not ensure it persists across a Flux instance crash. This can be
+ used to ensure critical data has been written to non-volatile storage.
+
+dir
+---
+
+.. program:: flux kvs dir
+
+Display all keys and their values under the directory *key*. Values that
+are too long to fit the terminal width are truncated with "..." appended.
+This command fails if *key* does not exist or is not a directory.
+If *key* is not provided, ``.`` (root of the namespace) is assumed.
+
+.. option:: -R, --recursive
+
+ Recursively display keys under subdirectories.
+
+.. option:: -d, --directory
+
+ List directory entries but not values.
+
+.. option:: -w, --width=N
+
+ Truncate values to fit in *N* columns instead of the terminal width.
+ Specify 0 to avoid truncation entirely.
+
+.. option:: -a, --at=TREEOBJ
+
+ Perform the directory lookup relative to a directory reference in
+ RFC 11 tree object format.
+
+ls
+--
+
+.. program:: flux kvs ls
+
+Display directory referred to by *key*, or "." (root) if unspecified. This
+sub-command is intended to mimic :linux:man1:`ls` behavior in a limited way.
+
+.. option:: -R, --recursive
+
+ List directory recursively.
+
+.. option:: -d, --directory
+
+ List directory instead of contents.
+
+.. option:: -w, --width=N
+
+ Limit output width to *N* columns. Specify 0 for unlimited output width.
+
+.. option:: -1, --1
+
+ Force one entry per line.
+
+.. option:: -F, --classify
+
+ Append key type indicator to key: ``.`` for directory. ``@`` for
+ symbolic link.
+
+unlink
+------
+
+.. program:: flux kvs unlink
+
+Remove key from the KVS.
+
+.. option:: -O, --treeobj-root
+
+ After the commit has completed, display the new root directory reference
+ in RFC 11 tree object format.
+
+.. option:: -b, --blobref
+
+ After the commit has completed, display the new root directory reference
+ as a single blobref.
+
+.. option:: -s, --sequence
+
+ After the commit has completed, display the new root sequence number
+ or "version".
+
+.. option:: -R, --recursive
+
+ Specify recursive removal of a directory.
+
+.. option:: -f, --force
+
+ Ignore nonexistent keys.
+
+link
+----
+
+.. program:: flux kvs link
+
+Create a new name for *target*, similar to a symbolic link. *target* does not
+have to exist. If *linkname* exists, it is overwritten.
+
+.. option:: -T, --target-namespace=NAME
+
+ Specify an alternate namespace for *target*. By default, *target* is
+ in the same namespace as *linkname*.
+
+.. option:: -O, --treeobj-root
+
+ After the commit has completed, display the new root directory reference
+ in RFC 11 tree object format.
+
+.. option:: -b, --blobref
+
+ After the commit has completed, display the new root directory reference
+ as a single blobref.
+
+.. option:: -s, --sequence
+
+ After the commit has completed, display the new root sequence number
+ or "version".
+
+readlink
+---------
+
+.. program:: flux kvs readlink
+
+Print the symbolic link target of *key*. The target may be another key name,
+or a :option:`namespace::key` tuple. It is an error if *key* is not a
+symbolic link.
+
+.. option:: -a, --at=TREEOBJ
+
+ Perform the lookup relative to a directory reference in RFC 11 tree object
+ format.
+
+.. option:: -o, --namespace-only
+
+ Print only the namespace name if the target has a namespace prefix.
+
+.. option:: -k, --key-only
+
+ Print only the key if the target has a namespace prefix.
+
+mkdir
+-----
+
+.. program:: flux kvs mkdir
+
+Create an empty directory. If *key* exists, it is overwritten.
+
+.. option:: -O, --treeobj-root
+
+ After the commit has completed, display the new root directory reference
+ in RFC 11 tree object format.
+
+.. option:: -b, --blobref
+
+ After the commit has completed, display the new root directory reference
+ as a single blobref.
+
+.. option:: -s, --sequence
+
+ After the commit has completed, display the new root sequence number
+ or "version".
+
+dropcache
+---------
+
+.. program:: flux kvs dropcache
+
+Tell the local KVS to drop any cache it is holding.
+
+.. option:: -a, --all
+
+ Publish an event across the Flux instance instructing the KVS module on
+ all ranks to drop their caches.
+
+copy
+----
+
+.. program:: flux kvs copy
+
+Copy *source* key to *destination* key. If a directory is copied, a new
+reference is created.
+
+.. option:: -S, --src-namespace=NAME
+
+ Specify the source namespace. By default, the primary KVS namespace
+ or the value of :envvar:`FLUX_KVS_NAMESPACE` is used.
+
+.. option:: -D, --dst-namespace=NAME
+
+ Specify the destination namespace. By default, the primary KVS namespace
+ or the value of :envvar:`FLUX_KVS_NAMESPACE` is used.
+
+move
+----
+
+.. program:: flux kvs move
+
+Copy *source* key to *destination* key and unlink *source*.
+
+.. option:: -S, --src-namespace=NAME
+
+ Specify the source namespace. By default, the primary KVS namespace
+ or the value of :envvar:`FLUX_KVS_NAMESPACE` is used.
+
+.. option:: -D, --dst-namespace=NAME
+
+ Specify the destination namespace. By default, the primary KVS namespace
+ or the value of :envvar:`FLUX_KVS_NAMESPACE` is used.
+
+getroot
+-------
+
+.. program:: flux kvs getroot
+
+Retrieve the current KVS root directory reference, displaying it as an
+RFC 11 dirref object unless otherwise specified.
+
+.. option:: -o, --owner
+
+ Display the numerical user ID that owns the target namespace.
+
+.. option:: -b, --blobref
+
+ Display the root directory reference as a single blobref.
+
+.. option:: -s, --sequence
+
+ Display the root sequence number or "version".
+
+version
+-------
+
+.. program:: flux kvs version
+
+Display the current KVS version, an integer value. The version starts
+at zero and is incremented on each KVS commit. Note that some commits
+may be aggregated for performance and the version will be incremented
+once for the aggregation, so it cannot be used as a direct count of
+commit requests.
+
+wait
+----
+
+.. program:: flux kvs wait
+
+Block until the KVS version reaches *version* or greater. A simple form
+of synchronization between peers is: node A puts a value, commits it,
+reads version, sends version to node B. Node B waits for version, gets value.
+
+namespace create
+----------------
+
+.. program:: flux kvs namespace create
+
+Create a new KVS namespace.
+
+.. option:: -o, --owner=UID
+
+ Set the owner of the namespace to *UID*. If unspecified, the owner is
+ set to the Flux instance owner.
+
+.. option:: -r, --rootref=TREEOBJ
+
+ Initialize namespace with specific root directory reference
+ If unspecified, an empty directory is referenced.
+
+namespace remove
+----------------
+
+.. program:: flux kvs namespace remove
+
+Remove a KVS namespace. Removal is not guaranteed to be complete when
+the command returns.
+
+namespace list
+--------------
+
+.. program:: flux kvs namespace list
+
+List all current namespaces, with owner and flags.
+
+eventlog get
+------------
+
+.. program:: flux kvs eventlog get
+
+Display the contents of an RFC 18 KVS eventlog referred to by *key*.
+
+.. option:: -W, --waitcreate
+
+ If the key does not exist, wait until it does.
+
+.. option:: -w, --watch
+
+ Monitor the eventlog, displaying new events as they are appended.
+
+.. option:: -c, --count=N
+
+ With :option:`--watch`, exit once *N* events have been displayed.
+
+.. option:: -u, --unformatted
+
+ Display the eventlog in raw RFC 18 form.
+
+.. option:: -H, --human
+
+ Display the eventlog in human-readable form.
+
+.. option:: -L, --color[=WHEN]
+
+ Control output colorization. The optional argument *WHEN* can be one of
+ 'auto', 'never', or 'always'. The default value of *WHEN* if omitted is
+ 'always'. The default is 'auto' if the option is unused.
+
+eventlog append
+---------------
+
+.. program:: flux kvs eventlog append
+
+Append an event to an RFC 18 KVS eventlog referred to by *key*.
+The event *name* and optional *context* are specified on the command line.
+
+.. option:: -t, --timestamp=SEC
+
+ Specify timestamp in decimal seconds since the UNIX epoch (UTC), otherwise
+ the current wall clock is used.
+
+
+eventlog wait-event
+-------------------
+
+.. program:: flux kvs eventlog wait-event
+
+Wait for a specific *event* to occur in an RFC 18 KVS eventlog
+referred to by *key*.
+
+.. option:: -W, --waitcreate
+
+ If the key does not exist, wait until it does.
+
+.. option:: -t, --timeout=SEC
+
+ Timeout after *SEC* if the specified event has not occurred by then.
+
+.. option:: -u, --unformatted
+
+ Display the event(s) in raw RFC 18 form.
+
+.. option:: -q, --quiet
+
+ Do not display the matched event.
+
+.. option:: -v, --verbose
+
+ Display events prior to the matched event.
+
+.. option:: -H, --human
+
+ Display eventlog events in human-readable form.
+
+.. option:: -L, --color[=WHEN]
+
+ Control output colorization. The optional argument *WHEN* can be one of
+ 'auto', 'never', or 'always'. The default value of *WHEN* if omitted is
+ 'always'. The default is 'auto' if the option is unused.
+
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_11`
+
+:doc:`rfc:spec_18`
diff --git a/doc/man1/flux-logger.adoc b/doc/man1/flux-logger.adoc
deleted file mode 100644
index fc182da0e35a..000000000000
--- a/doc/man1/flux-logger.adoc
+++ /dev/null
@@ -1,59 +0,0 @@
-// flux-help-include: true
-FLUX-LOGGER(1)
-==============
-:doctype: manpage
-
-
-NAME
-----
-flux-logger - create a Flux log entry
-
-
-SYNOPSIS
---------
-*flux* *logger* ['--severity SEVERITY'] ['--appname NAME'] 'message' '...'
-
-
-DESCRIPTION
------------
-flux-logger(1) appends Flux log entries to the local Flux
-broker's circular buffer.
-
-Log entries are associated with a syslog(3) style severity.
-Valid severity names are 'emerg', 'alert', 'crit', 'err',
-'warning', 'notice', 'info', 'debug'.
-
-Log entries may also have a user-defined application name.
-This is different than the syslog 'facility', which is always set
-to LOG_USER in Flux log messages.
-
-The wall clock time (UTC) and the broker rank are added to the log
-message when it is created.
-
-OPTIONS
--------
-*-s, --severity*='SEVERITY'::
-Specify the log message severity. The default severity is 'info'.
-
-*-n, --appname*='NAME'::
-Specify a user-defined application name to associate with the log message.
-The default appname is 'logger'.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-flux-dmesg(1), flux_log(3), syslog(3)
diff --git a/doc/man1/flux-logger.rst b/doc/man1/flux-logger.rst
new file mode 100644
index 000000000000..f69136d62816
--- /dev/null
+++ b/doc/man1/flux-logger.rst
@@ -0,0 +1,53 @@
+==============
+flux-logger(1)
+==============
+
+
+SYNOPSIS
+========
+
+**flux** **logger** [*--severity SEVERITY*] [*--appname NAME*] *message* *...*
+
+DESCRIPTION
+===========
+
+.. program:: flux logger
+
+:program:`flux logger` appends Flux log entries to the local Flux
+broker's circular buffer.
+
+Log entries are associated with a :linux:man3:`syslog` style severity.
+Valid severity names are *emerg*, *alert*, *crit*, *err*,
+*warning*, *notice*, *info*, *debug*.
+
+Log entries may also have a user-defined application name.
+This is different than the syslog *facility*, which is always set
+to LOG_USER in Flux log messages.
+
+The wall clock time (UTC) and the broker rank are added to the log
+message when it is created.
+
+
+OPTIONS
+=======
+
+.. option:: -s, --severity=SEVERITY
+
+ Specify the log message severity. The default severity is *info*.
+
+.. option:: -n, --appname=NAME
+
+ Specify a user-defined application name to associate with the log message.
+ The default appname is *logger*.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-dmesg`, :man3:`flux_log`, :linux:man3:`syslog`
diff --git a/doc/man1/flux-mini.adoc b/doc/man1/flux-mini.adoc
deleted file mode 100644
index 2844b02a2e17..000000000000
--- a/doc/man1/flux-mini.adoc
+++ /dev/null
@@ -1,167 +0,0 @@
-// flux-help-include: true
-FLUX-MINI(1)
-============
-:doctype: manpage
-
-
-NAME
-----
-flux-mini - Minimal Job Submission Tool
-
-
-SYNOPSIS
---------
-*flux* *mini* *submit* [OPTIONS] ['--ntasks=N'] COMMAND...
-
-*flux* *mini* *run* [OPTIONS] ['--ntasks=N'] COMMAND...
-
-
-DESCRIPTION
------------
-flux-mini(1) submits jobs to run under Flux. The job consists of
-'N' copies of COMMAND launched together as a parallel job.
-If '--ntasks' is unspecified, a value of 'N=1' is assumed.
-
-The *submit* command enqueues the job and prints its numerical Job ID
-on standard output.
-
-The *run* command does the same interactively, blocking until the job
-has completed.
-
-The intent is for the "mini" commands to remain simple with stable interfaces
-over time, making them suitable for use in scripts. For advanced usage,
-see flux-run(1) and flux-submit(1).
-
-The available OPTIONS are detailed below.
-
-
-JOB PARAMETERS
---------------
-These commands accept only the simplest parameters for expressing
-the size of the parallel program and the geometry of its task slots:
-
-*-n, --ntasks=N*::
-Set the number of tasks to launch (default 1).
-
-*-c, --cores-per-task=N*::
-Set the number of cores to assign to each task (default 1).
-
-*-g, --gpus-per-task=N*::
-Set the number of GPU devices to assign to each task (default none).
-
-*-N, --nodes=N*::
-Set the number of nodes to assign to the job. Tasks will be distributed
-evenly across the allocated nodes. It is an error to request more nodes
-than there are tasks. If unspecified, the number of nodes will be chosen
-by the scheduler.
-
-*-t, --time-limit=FSD*::
-Set a time limit for the job in Flux standard duration (RFC 23).
-FSD is a floating point number with a single character units suffix
-("s", "m", "h", or "d"). If unspecified, the job is subject to the
-system default time limit.
-
-
-STANDARD I/O
-------------
-By default, task stdout and stderr streams are redirected to the
-KVS, where they may be accessed with the `flux job attach` command.
-
-In addition, `flux-mini run` processes standard I/O in real time,
-emitting the job's I/O to its stdout and stderr.
-
-*--output=FILENAME*::
-Redirect stdout to the specified FILENAME, bypassing the KVS.
-The mustache template '{{id}}' is expanded to the numerical Job ID,
-useful to ensure FILENAME is unique across multiple jobs.
-
-*--error=FILENAME*::
-Redirect stderr to the specified FILENAME, bypassing the KVS.
-The mustache template '{{id}}' is expanded as above.
-
-*--label-io*::
-Add task rank prefixes to each line of output.
-
-
-EXIT STATUS
------------
-The job exit status, normally the largest task exit status, is stored
-in the KVS. If one or more tasks are terminated with a signal,
-the job exit status is 128+signo.
-
-The `flux-job attach` command exits with the job exit status.
-
-In addition, `flux-mini run` runs until the job completes and exits
-with the job exit status.
-
-
-OTHER OPTIONS
--------------
-*--priority=N*::
-Specify job priority, which affects queue order. Numerically higher priority
-jobs are considered by the scheduler first. Guests may submit jobs with
-priority in the range of 0 to 16, while instance owners may submit jobs
-with priority in the range of 0 to 31 (default 16).
-
-*-v, --verbose*::
-_(run only)_ Increase verbosity on stderr. For example, currently `-v`
-displays jobid, `-vv` displays job events, and `-vvv` displays exec events.
-The specific output may change in the future.
-
-*-o, --setopt=KEY[=VAL]*::
-Set shell option. Keys may include periods to denote hierarchy.
-VAL is optional and may be valid JSON (bare values, objects, or arrays),
-otherwise VAL is interpreted as a string. If VAL is not set, then the
-default value is 1. See SHELL OPTIONS below.
-
-*--setattr=KEY=VAL*::
-Set jobspec attribute. Keys may include periods to denote hierarchy.
-VAL may be valid JSON (bare values, objects, or arrays), otherwise VAL
-is interpreted as a string.
-
-*--dry-run*::
-Don't actually submit the job. Just emit jobspec on stdout and exit.
-
-*--debug*::
-Enable job debug events, primarily for debugging Flux itself.
-The specific effects of this option may change in the future.
-
-
-SHELL OPTIONS
--------------
-These options are provided by built-in shell plugins that may be
-overridden in some cases:
-
-*mpi=spectrum*::
-Load the MPI personality plugin for IBM Spectrum MPI. All other MPI
-plugins are loaded by default.
-
-*affinity=per-task*::
-Tasks are distributed across the assigned resources.
-
-*affinity=off*::
-Disable task affinity plugin.
-
-*gpu-affinity=per-task*::
-GPU devices are distributed evenly among local tasks. Otherwise,
-GPU device affinity is to the job.
-
-*gpu-affinity=off*::
-Disable GPU affinity for this job.
-
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
diff --git a/doc/man1/flux-module.adoc b/doc/man1/flux-module.adoc
deleted file mode 100644
index bdc7095c48cf..000000000000
--- a/doc/man1/flux-module.adoc
+++ /dev/null
@@ -1,158 +0,0 @@
-// flux-help-include: true
-FLUX-MODULE(1)
-==============
-:doctype: manpage
-
-
-NAME
-----
-flux-module - manage Flux extension modules
-
-
-SYNOPSIS
---------
-*flux* *module* 'COMMAND' ['OPTIONS']
-
-
-DESCRIPTION
------------
-flux-module(1) manages dynamically loadable Flux modules.
-It can load/remove/list modules for the flux-broker(1), and for other
-Flux services that support dynamic module extensions.
-
-
-COMMANDS
---------
-*info* ['name']::
-Display information about module 'name'.
-If 'name' includes a slash '/' character, it is interpreted as a
-file path, and the module name is then determined by reading the
-*mod_name* symbol. Otherwise, FLUX_MODULE_PATH is searched for a module
-with *mod_name* equal to 'name'.
-
-*load* 'name' ['module-arguments' ...]::
-Load module 'name', interpreted as described above.
-The service that will load the module is inferred
-from the module name. When the load command completes successfully,
-the new module is ready to accept messages on all targeted ranks.
-
-*remove* [--force] 'name'::
-Remove module 'name'. The service that will unload the module is
-inferred from the name specified on the command line. If '-f, --force'
-is used, then do not error if module 'name' is not loaded.
-
-*reload* [--force] 'name' ['module-arguments' ...]::
-Reload module 'name'. This is equivalent to running 'flux module remove'
-followed by 'flux module load'. It is a fatal error if module 'name' is
-not loaded during removal unless the `-f, --force` option is specified.
-
-*list* ['service']::
-List modules loaded by 'service', or by flux-broker(1) if 'service' is unspecified.
-
-*stats* ['OPTIONS'] ['name']::
-Request statistics from module 'name'. A JSON object containing a set of
-counters for each type of Flux message is returned by default, however
-the object may be customized on a module basis.
-
-*debug* ['OPTIONS'] ['name']::
-Manipulate debug flags in module 'name'. The interpretation of debug
-flag bits is private to the module and its test drivers.
-
-STATS OPTIONS
--------------
-*-p, --parse*'=OBJNAME'::
-OBJNAME is a period delimited list of field names that should be walked
-to obtain a specific value or object in the returned JSON.
-
-*-t, --type*'=int|double'::
-Force the returned value to be converted to int or double.
-
-*-s, --scale*'=N'::
-Multiply the returned (int or double) value by the specified
-floating point value.
-
-*-R, --rusage*::
-Return a JSON object representing an 'rusage' structure
-returned by getrusage(2).
-
-*-c, --clear*::
-Send a request message to clear statistics in the target module.
-
-*-C, --clear-all*::
-Broadcast an event message to clear statistics in the target module
-on all ranks.
-
-DEBUG OPTIONS
--------------
-
-*-c, --clear*::
-Set debug flags to zero.
-
-*-S, --set*'=MASK'::
-Set debug flags to MASK.
-The value may be prefixed with 0x to indicate hexadecimal or 0
-to indicate octal, otherwise the value is interpreted as decimal.
-
-*-c, --clearbit*'=MASK'::
-Clear the debug bits specified in MASK without disturbing other bits.
-The value is interpreted as above.
-
-*-s, --setbit*'=MASK'::
-Set the debug bits specified in MASK without disturbing other bits.
-The value is interpreted as above.
-
-LIST OUTPUT
------------
-
-The 'list' command displays one line for each unique (as determined by
-SHA1 hash) module loaded by a service.
-
-*Module*::
-The value of the *mod_name* symbol for this module.
-
-*Size*::
-The size in bytes of the module .so file.
-
-*Digest*::
-The last 7 characters of the SHA1 digest of the contents of
-the module .so file.
-
-*Idle*::
-Idle times are defined for flux-broker(1) comms modules as the number of
-heartbeats since the module last sent a request or response message.
-The idle time may be defined differently for other services, or have no
-meaning.
-
-
-MODULE SYMBOLS
---------------
-All Flux modules define the following global symbols:
-
-*const char *mod_name;*::
-A null-terminated string defining the module name.
-Module names are words delimited by periods, with the service that
-will load the module indicated by the words that prefix the final one.
-If there is no prefix, the module is loaded by flux-broker(1).
-
-*int mod_main (void *context, int argc, char **argv);*::
-An entry function.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-syslog(3)
diff --git a/doc/man1/flux-module.rst b/doc/man1/flux-module.rst
new file mode 100644
index 000000000000..e8c7d8ed33b0
--- /dev/null
+++ b/doc/man1/flux-module.rst
@@ -0,0 +1,268 @@
+==============
+flux-module(1)
+==============
+
+
+SYNOPSIS
+========
+
+| **flux** **module** **load** [*--name*] *module* [*args...*]
+| **flux** **module** **reload** [*--name*] [*--force*] *module* [*args...*]
+| **flux** **module** **remove** [*--force*] *name*
+| **flux** **module** **list** [*-l*]
+| **flux** **module** **stats** [*-R*] [*--clear*] *name*
+| **flux** **module** **debug** [*--setbit=VAL*] [*--clearbit=VAL*] [*--set=MASK*] [*--clear=MASK*] *name*
+| **flux** **module** **trace** [-f] [*-t TYPE,...*] [-T *topic-glob*] *name...*
+
+
+
+DESCRIPTION
+===========
+
+.. program:: flux module
+
+:program:`flux module` manages dynamically loadable :man1:`flux-broker` modules.
+
+
+COMMANDS
+========
+
+load
+----
+
+.. program:: flux module load
+
+Load *module*, which may be either the path to a shared object file, including
+the ``.so`` suffix, or the basename of a shared object file on the
+:envvar:`FLUX_MODULE_PATH`, without the suffix.
+
+When :program:`flux module load` completes successfully, the new module has
+entered the running state (see LIST OUTPUT below).
+
+.. option:: -n, --name=NAME
+
+ Override the default module name. A single shared object file may be
+ loaded multiple times under different names.
+
+reload
+------
+
+.. program:: flux module reload
+
+Reload module *name*. This is equivalent to running
+:program:`flux module remove` followed by :program:`flux module load`.
+
+.. option:: -f, --force
+
+ Suppress failure if *module* is not loaded and proceed with loading.
+
+.. option:: -n, --name=NAME
+
+ Override the default module name.
+
+remove
+------
+
+.. program:: flux module reload
+
+Remove module *name*.
+
+.. option:: -f, --force
+
+ Suppress failure if module *name* is not loaded.
+
+list
+----
+
+.. program:: flux module list
+
+List the loaded modules.
+
+.. option:: -l, --long
+
+ Include the full DSO path for each module.
+
+stats
+-----
+
+.. program:: flux module stats
+
+Request statistics from module *name*. A JSON object containing a set of
+counters for each type of Flux message is returned by default, however
+the object may be customized on a module basis.
+
+.. option:: -p, --parse=OBJNAME
+
+ *OBJNAME* is a period delimited list of field names that should be walked
+ to obtain a specific value or object in the returned JSON.
+
+.. option:: -t, --type=int|double
+
+ Force the returned value to be converted to int or double.
+
+.. option:: -s, --scale=N
+
+ Multiply the returned (int or double) value by the specified
+ floating point value.
+
+.. option:: -R, --rusage=[self|children|thread]
+
+ Return a JSON object representing an *rusage* structure
+ returned by :linux:man2:`getrusage`. If specified, the optional argument
+ specifies the query target (default: self).
+
+.. option:: -c, --clear
+
+ Send a request message to clear statistics in the target module.
+
+.. option:: -C, --clear-all
+
+ Broadcast an event message to clear statistics in the target module
+ on all ranks.
+
+debug
+-----
+
+.. program:: flux module debug
+
+Manipulate debug flags in module *name*. The interpretation of debug
+flag bits is private to the module and its test drivers.
+
+.. option:: -C, --clear
+
+ Set all debug flags to 0.
+
+.. option:: -S, --set=MASK
+
+ Set debug flags to *MASK*.
+
+.. option:: -s, --setbit=VAL
+
+ Set one debug flag *VAL* to 1.
+
+.. option:: -c, --clearbit=VAL
+
+ Set one debug flag *VAL* to 0.
+
+trace
+-----
+
+.. program:: flux module trace
+
+Display message summaries for messages transmitted and received by the
+named modules.
+
+.. option:: -f, --full
+
+ Include JSON payload in output, if any. Payloads that are not JSON are
+ not displayed.
+
+.. option:: -T, --topic=GLOB
+
+ Filter output by topic string.
+
+.. option:: -t, --type=TYPE,...
+
+ Filter output by message type, a comma-separated list. Valid types are
+ ``request``, ``response``, ``event``, or ``control``.
+
+.. option:: -L, --color=WHEN
+
+ Colorize output when supported; WHEN can be ``always`` (default if omitted),
+ ``never``, or ``auto`` (default).
+
+.. option:: -H, --human
+
+ Display human-readable output. See also :option:`--color` and
+ :option:`--delta`.
+
+.. option:: -d, --delta
+
+ With :option:`--human`, display the time delta between messages instead
+ of a relative offset since the last absolute timestamp.
+
+
+DEBUG OPTIONS
+=============
+
+.. program:: flux module debug
+
+.. option:: -c, --clear
+
+ Set debug flags to zero.
+
+.. option:: -S, --set=MASK
+
+ Set debug flags to MASK.
+ The value may be prefixed with 0x to indicate hexadecimal or 0
+ to indicate octal, otherwise the value is interpreted as decimal.
+
+.. option:: -c, --clearbit=MASK
+
+ Clear the debug bits specified in MASK without disturbing other bits.
+ The value is interpreted as above.
+
+.. option:: -s, --setbit=MASK
+
+ Set the debug bits specified in MASK without disturbing other bits.
+ The value is interpreted as above.
+
+
+LIST OUTPUT
+===========
+
+.. program:: flux module list
+
+The *list* command displays one line for each unique (as determined by
+SHA1 hash) loaded module.
+
+**Module**
+ The value of the **mod_name** symbol for this module.
+
+**Idle**
+ Idle times are defined as the number of seconds since the module last sent
+ a request or response message.
+
+**State**
+ The state of the module is shown as a single character: *I* initializing,
+ *R* running, *F* finalizing, *E* exited. A module automatically enters
+ running state when it calls :man3:`flux_reactor_run`. It can transition
+ earlier by calling `flux_module_set_running()`.
+
+**Service**
+ If the module has registered additional services, the service names are
+ displayed in a comma-separated list.
+
+**Path**
+ The full path to the broker module shared object file (only shown with
+ the **-l, --long** option).
+
+
+MODULE SYMBOLS
+==============
+
+All Flux modules define the following global symbols:
+
+**const char \*mod_name;**
+ A null-terminated string defining the module name.
+
+**int mod_main (void \*context, int argc, char \**argv);**
+ An entry function.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_5`
+
+
+SEE ALSO
+========
+
+:linux:man3:`syslog`
diff --git a/doc/man1/flux-overlay.rst b/doc/man1/flux-overlay.rst
new file mode 100644
index 000000000000..1702b99cbfec
--- /dev/null
+++ b/doc/man1/flux-overlay.rst
@@ -0,0 +1,286 @@
+.. flux-help-description: Show flux overlay network status
+.. flux-help-section: instance
+
+===============
+flux-overlay(1)
+===============
+
+
+SYNOPSIS
+========
+
+| **flux** **overlay** **status** [*-v*] [*--timeout=FSD*] [*--rank=N*]
+| **flux** **overlay** **errors** [*--timeout=FSD*]
+| **flux** **overlay** **lookup** *target*
+| **flux** **overlay** **parentof** *rank*
+| **flux** **overlay** **disconnect** [*--parent=RANK*] *target*
+| **flux** **overlay** **trace** [-f] [*-r rank*] [*-t TYPE,...*] [*topic-glob*]
+
+
+DESCRIPTION
+===========
+
+.. program:: flux overlay
+
+:program:`flux overlay` is a utility for the Flux tree based overlay network.
+
+COMMANDS
+========
+
+status
+------
+
+.. program:: flux overlay status
+
+:program:`flux overlay status` reports the current status of the tree based
+overlay network. The possible status values are shown in `SUBTREE STATUS`_
+below.
+
+.. option:: -r, --rank=[RANK]
+
+ Check health of sub-tree rooted at NODEID (default 0).
+
+.. option:: -v, --verbose=[LEVEL]
+
+ Increase reporting detail: 1=show time since current state was entered,
+ 2=show round-trip RPC times.
+
+.. option:: -t, --timeout=FSD
+
+ Set RPC timeout, 0=disable (default 0.5s)
+
+.. option:: --summary
+
+ Show only the root sub-tree status.
+
+.. option:: --down
+
+ Show only the partial/degraded sub-trees.
+
+.. option:: --no-pretty
+
+ Do not indent entries and use line drawing characters to show overlay
+ tree structure
+
+.. option:: --no-ghost
+
+ Do not fill in presumed state of nodes that are inaccessible behind
+ offline/lost overlay parents.
+
+.. option:: -L, --color=WHEN
+
+ Colorize output when supported; WHEN can be 'always' (default if omitted),
+ 'never', or 'auto' (default).
+
+.. option:: -H, --highlight=TARGET
+
+ Highlight one or more targets and their ancestors.
+
+.. option:: -w, --wait=STATE
+
+ Wait until sub-tree enters *STATE* before reporting (full, partial, offline,
+ degraded, lost).
+
+errors
+------
+
+.. program:: flux overlay errors
+
+:program:`flux overlay errors` summarizes any errors recorded for lost or
+offline nodes. The output consists of one line per unique error with a
+hostlist prefix.
+
+.. option:: -t, --timeout=FSD
+
+ Set RPC timeout, 0=disable (default 0.5s)
+
+lookup
+------
+
+.. program:: flux overlay lookup
+
+Translate a hostlist *target* to a rank idset or a rank idset *target* to
+hostlist.
+
+parentof
+--------
+
+.. program:: flux overlay parentof
+
+Show the parent of *rank*.
+
+disconnect
+----------
+
+.. program:: flux overlay disconnect
+
+Disconnect a subtree rooted at *target* (hostname or rank).
+
+.. option:: -r, --parent=NODEID
+
+ Set parent rank to *NODEID*. By default, the parent is determined from
+ the topology.
+
+trace
+-----
+
+.. program:: flux overlay trace
+
+Display message summaries for messages transmitted and received on the
+overlay network. A topic string glob pattern may be supplied as a positional
+argument.
+
+.. option:: -f, --full
+
+ Include JSON payload in output, if any. Payloads that are not JSON are
+ not displayed.
+
+.. option:: -r, --rank=NODEID
+
+ Filter output by overlay network peer rank. Note that this rank is not
+ necessarily the same as the message source or destination.
+
+.. option:: -t, --type=TYPE,...
+
+ Filter output by message type, a comma-separated list. Valid types are
+ ``request``, ``response``, ``event``, or ``control``.
+
+.. option:: -L, --color=WHEN
+
+ Colorize output when supported; WHEN can be ``always`` (default if omitted),
+ ``never``, or ``auto`` (default).
+
+.. option:: -H, --human
+
+ Display human-readable output. See also :option:`--color` and
+ :option:`--delta`.
+
+.. option:: -d, --delta
+
+ With :option:`--human`, display the time delta between messages instead
+ of a relative offset since the last absolute timestamp.
+
+
+
+EXAMPLES
+========
+
+By default, :program:`flux overlay status` shows the status of the full
+Flux instance in graphical form, e.g.
+
+::
+
+ $ flux overlay status
+ 0 test0: partial
+ ââ 1 test1: offline
+ ââ 2 test2: full
+ ââ 3 test3: full
+ ââ 4 test4: full
+ ââ 5 test5: offline
+ ââ 6 test6: full
+ ââ 7 test7: offline
+
+The time in the current state is reported if ``-v`` is added, e.g.
+
+::
+
+ $ flux overlay status -v
+ 0 test0: partial for 2.55448m
+ ââ 1 test1: offline for 12.7273h
+ ââ 2 test2: full for 2.55484m
+ ââ 3 test3: full for 18.2725h
+ ââ 4 test4: full for 18.2777h
+ ââ 5 test5: offline for 12.7273h
+ ââ 6 test6: full for 18.2784h
+ ââ 7 test7: offline for 12.7273h
+
+Round trip RPC times are shown with ``-vv``, e.g.
+
+::
+
+ 0 test0: partial for 4.15692m (2.982 ms)
+ ââ 1 test1: offline for 12.754h
+ ââ 2 test2: full for 4.15755m (2.161 ms)
+ ââ 3 test3: full for 18.2992h (2.332 ms)
+ ââ 4 test4: full for 18.3045h (2.182 ms)
+ ââ 5 test5: offline for 12.754h
+ ââ 6 test6: full for 18.3052h (2.131 ms)
+ ââ 7 test7: offline for 12.754h
+
+
+
+::
+
+At times an error summary for *lost* nodes may be useful, e.g.
+
+::
+
+ $ flux overlay errors
+ test[2,5]: lost connection
+ test[6-7]: lost parent
+
+A broker that is not responding but is not shown as *lost* or *offline* may
+be forcibly disconnected from the overlay network with
+
+::
+
+ $ flux overlay disconnect 2
+ flux-overlay: asking test0 (rank 0) to disconnect child test2 (rank 2)
+
+However, before doing that it may be useful to see if a broker acting as a
+router to that node is actually the problem. The parent of a broker rank may
+be listed with
+
+::
+
+ $ flux overlay parentof 2
+ 0
+
+Finally, translation between hostnames and broker ranks is accomplished with
+
+::
+
+ $ flux overlay lookup 2
+ test2
+ $ flux overlay lookup test2
+ 2
+
+
+SUBTREE STATUS
+==============
+
+The possible overlay subtree status values are:
+
+full
+ Node is online and no children are in *partial*, *offline*, *degraded*, or
+ *lost* state.
+
+partial
+ Node is online, and some children are in *partial* or *offline* state; no
+ children are in *degraded* or *lost* state.
+
+degraded
+ Node is online, and some children are in *degraded* or *lost* state.
+
+lost
+ Node has gone missing, from the parent perspective.
+
+offline
+ Node has not yet joined the instance, or has been cleanly shut down.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_3`
+
+
+SEE ALSO
+========
+
+:man1:`flux-ping`
diff --git a/doc/man1/flux-pgrep.rst b/doc/man1/flux-pgrep.rst
new file mode 100644
index 000000000000..9005a084f197
--- /dev/null
+++ b/doc/man1/flux-pgrep.rst
@@ -0,0 +1,113 @@
+.. flux-help-include: true
+.. flux-help-section: jobs
+.. flux-help-command: pgrep/pkill
+
+==============
+flux-pgrep(1)
+==============
+
+
+SYNOPSIS
+========
+
+**flux** **pgrep** [*OPTIONS*] expression..
+
+**flux** **pkill** [*OPTIONS*] expression..
+
+DESCRIPTION
+===========
+
+.. program:: flux pgrep
+
+:program:`flux pgrep` lists jobids that match a supplied expression. The
+expression may contain a pattern which matches the job name, or
+a range of jobids in the form ``jobid1..jobid2``. If both a pattern
+and jobid range are supplied then both must match.
+
+In rare cases, a pattern may appear to be a jobid range, when the
+pattern ``..`` is used and the strings on both sides area also valid
+Flux jobids. In that case, a name pattern match can be forced by
+prefixing the pattern with ``name:``, e.g. ``name:fr..123``.
+
+By default, only active jobs for the current user are considered.
+
+:program:`flux pkill` cancels matching jobs instead of listing them.
+
+OPTIONS
+=======
+
+.. option:: -a
+
+ Include jobs in all states, including inactive jobs.
+ This is shorthand for :option:`--filter=pending,running,inactive`.
+ (pgrep only)
+
+.. option:: -A
+
+ Include jobs for all users. This is shorthand for :option:`--user=-all`.
+
+.. option:: -u, --user=USER
+
+ Fetch jobs only for the given user, instead of the current UID.
+
+.. option:: -f, --filter=STATE|RESULT
+
+ Include jobs with specific job state or result. Multiple states or
+ results can be listed separated by comma. See the JOB STATUS section
+ of the :man1:`flux-jobs` manual for more detail.
+
+.. option:: -q, --queue=QUEUE[,...]
+
+ Only include jobs in the named queue *QUEUE*. Multiple queues may be
+ specified as a comma-separated list, or by using the :option:`--queue`
+ option multiple times.
+
+.. option:: -c, --count=N
+
+ Limit output to the first *N* matches (default 1000).
+
+.. option:: --max-entries=N
+
+ Limit the number of jobs to consider to *N* entries (default 1000).
+
+.. option:: -o, --format=NAME|FORMAT
+
+ Specify a named output format *NAME* or a format string using Python's
+ format syntax. An alternate default format can be set via the
+ :envvar:`FLUX_PGREP_FORMAT_DEFAULT` environment variable. For full
+ documentation of this option, including supported field names and format
+ configuration options, see :man1:flux-jobs. This command shares configured
+ named formats with *flux-jobs* by reading *flux-jobs* configuration files.
+ Supported builtin named formats include *default*, *full*, *long*, and
+ *deps*. The default format emits the matched jobids only. (pgrep only)
+
+.. option:: -n, --no-header
+
+ Suppress printing of the header line. (pgrep only)
+
+.. option:: -w, --wait
+
+ Wait for jobs to finish after cancel. (pkill only)
+
+EXIT STATUS
+===========
+
+0
+ One or more jobs matched the supplied expression. For *pkill* the
+ process have also been successfully canceled.
+
+1
+ No jobs matched or there was an error canceling them.
+
+2
+ Syntax or other command line error.
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+SEE ALSO
+========
+
+:man1:`flux-jobs`
diff --git a/doc/man1/flux-ping.adoc b/doc/man1/flux-ping.adoc
deleted file mode 100644
index f2a91766c705..000000000000
--- a/doc/man1/flux-ping.adoc
+++ /dev/null
@@ -1,96 +0,0 @@
-// flux-help-include: true
-FLUX-PING(1)
-============
-:doctype: manpage
-
-
-NAME
-----
-flux-ping - measure round-trip latency to Flux services
-
-
-SYNOPSIS
---------
-*flux* *ping* ['OPTIONS'] target
-
-
-DESCRIPTION
------------
-flux-ping(1) measures round-trip latency to a Flux service implementing
-the "ping" method in a manner analogous to ping(8). The ping response is
-essentially an echo of the request, with the route taken to the service
-added by the service. This route is displayed in the output and can
-give insight into how various addresses are routed.
-
-'target' may be the name of a comms module service, e.g. "kvs".
-flux-ping(1) will send a request to "kvs.ping". As a shorthand,
-'target' can include a rank prefix delimited by an exclamation point.
-"flux ping 4!kvs" is equivalent to "flux ping --rank 4 kvs" (see --rank
-option below). Don't forget to quote the exclamation point if it is
-interpreted by your shell.
-
-As a shorthand, 'target' may also simply be a rank by itself
-indicating that the broker on that rank or ranks, rather than a comms
-module, is to be pinged. "flux ping 1" is equivalent to
-"flux ping --rank 1 cmb".
-
-OPTIONS
--------
-*-r, --rank*'=N'::
-Find target on a specific broker rank. Special case strings ``_any_''
-and ``_upstream_'' available to ping FLUX_NODEID_ANY and FLUX_NODEID_UPSTREAM
-respectively. Default: send to ``_any_''.
-
-*-p, --pad*'=N'::
-Include in the payload a string of length 'N' bytes. The payload will be
-echoed back in the response. This option can be used to explore the
-effect of message size on latency. Default: no padding.
-
-*-i, --interval*'=N'::
-Specify the delay, in seconds, between successive requests.
-A value of zero is valid and indicates that there should be no delay.
-Requests are sent without waiting for responses. Default: 1.0 seconds.
-
-*-c, --count*'=N'::
-Specify the number of requests to send, and terminate the command once
-responses have been received for all the requests. Default: unlimited.
-
-*-b, --batch*::
-Begin processing responses after all requests are sent. Requires --count.
-
-*-u, --userid*::
-Include userid and rolemask of original request, which are echoed back
-in ping response, in ping output.
-
-EXAMPLES
---------
-
-One can ping a service by name, e.g.
-
- $ flux ping kvs
- kvs.ping pad=0 seq=0 time=0.774 ms (0EB02!A3368!0!382A6)
- kvs.ping pad=0 seq=1 time=0.686 ms (0EB02!A3368!0!382A6)
- ...
-
-This tells you that the local "kvs" comms module is alive and the
-round-trip latency is a bit over half a millisecond. The route hops are:
-
- 0EB02: UUID of the ping command
- A3368: UUID of the API module
- 0: rank of the local broker
- 382A6: UUID of the KVS module.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
diff --git a/doc/man1/flux-ping.rst b/doc/man1/flux-ping.rst
new file mode 100644
index 000000000000..c714174a3393
--- /dev/null
+++ b/doc/man1/flux-ping.rst
@@ -0,0 +1,100 @@
+============
+flux-ping(1)
+============
+
+
+SYNOPSIS
+========
+
+**flux** **ping** [*OPTIONS*] target
+
+
+DESCRIPTION
+===========
+
+.. program:: flux ping
+
+:program:`flux ping` measures round-trip latency to a Flux service implementing
+the "ping" method in a manner analogous to ping(8). The ping response is
+essentially an echo of the request, with the route taken to the service
+added by the service. This route is displayed in the output and can
+give insight into how various addresses are routed.
+
+*target* may be the name of a Flux service, e.g. "kvs".
+:program:`flux ping` will send a request to "kvs.ping". As a shorthand,
+*target* can include a rank or host prefix delimited by an exclamation point.
+:program:`flux ping 4!kvs` is equivalent to :option:`flux ping --rank 4 kvs`
+(see :option:`--rank` option below). Don't forget to quote the exclamation
+point if it is interpreted by your shell.
+
+As a shorthand, *target* may also simply be a rank or host by itself
+indicating that the broker on that rank/host, rather than a Flux
+service, is to be pinged. :command:`flux ping 1` is equivalent to
+:option:`flux ping --rank 1 broker`.
+
+
+OPTIONS
+=======
+
+.. option:: -r, --rank=N
+
+ Find target on a specific broker rank. Special case strings â*any*â
+ and â*upstream*â available to ping FLUX_NODEID_ANY and FLUX_NODEID_UPSTREAM
+ respectively. Default: send to â*any*â.
+
+.. option:: -p, --pad=N
+
+ Include in the payload a string of length *N* bytes. *N* may be a
+ floating point number with optional multiplicative suffix k,K=1024,
+ M=1024\*1024, or G=1024\*1024\*1024. The payload will be echoed back in
+ the response. This option can be used to explore the effect of message
+ size on latency. Default: no padding.
+
+.. option:: -i, --interval=Ns
+
+ Specify the delay, in seconds, between successive requests.
+ A value of zero is valid and indicates that there should be no delay.
+ Requests are sent without waiting for responses. Default: 1.0 seconds.
+
+.. option:: -c, --count=N
+
+ Specify the number of requests to send, and terminate the command once
+ responses have been received for all the requests. Default: unlimited.
+
+.. option:: -b, --batch
+
+ Begin processing responses after all requests are sent. Requires --count.
+
+.. option:: -u, --userid
+
+ Include userid and rolemask of original request, which are echoed back
+ in ping response, in ping output.
+
+
+EXAMPLES
+========
+
+One can ping a service by name, e.g.
+
+::
+
+ $ flux ping kvs
+ kvs.ping pad=0 seq=0 time=0.774 ms (0EB02!A3368!0!382A6)
+ kvs.ping pad=0 seq=1 time=0.686 ms (0EB02!A3368!0!382A6)
+ ...
+
+This tells you that the local "kvs" service is alive and the
+round-trip latency is a bit over half a millisecond. The route hops are:
+
+::
+
+ 0EB02: UUID of the ping command
+ A3368: UUID of the API module
+ 0: rank of the local broker
+ 382A6: UUID of the KVS module.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
diff --git a/doc/man1/flux-pmi.rst b/doc/man1/flux-pmi.rst
new file mode 100644
index 000000000000..481f643d10d0
--- /dev/null
+++ b/doc/man1/flux-pmi.rst
@@ -0,0 +1,141 @@
+===========
+flux-pmi(1)
+===========
+
+
+SYNOPSIS
+========
+
+| [**launcher**] **flux-pmi** [*-v*] [*--method=URI*] barrier [*--count=N*]
+| [**launcher**] **flux-pmi** [*-v*] [*--method=URI*] exchange [*--count=N*]
+| [**launcher**] **flux-pmi** [*-v*] [*--method=URI*] get [*--ranks=IDSET*]
+
+
+DESCRIPTION
+===========
+
+.. program:: flux pmi
+
+:program:`flux pmi` is a standalone Process Management Interface (PMI) client
+that embeds the same PMI client plugins as :man1:`flux-broker`. It can be
+used to test the PMI service offered by :man1:`flux-shell` to parallel
+programs launched by Flux, or to probe the PMI services of an external
+launcher like Slurm or Hydra in isolation, without the complications of
+starting a Flux instance.
+
+:program:`flux pmi` tries a sequence of PMI plugins until one successfully
+initializes. Alternatively, the specific plugin can be forced with the
+:option:`--method` option. Initialization is followed by a subcommand-specific
+sequence of PMI operations that mimics a common pattern, and then PMI
+finalization.
+
+OPTIONS
+=======
+
+.. option:: -v, --verbose[=LEVEL]
+
+ Trace PMI operations. This is equivalent to setting
+ :envvar:`FLUX_PMI_DEBUG` in the broker environment.
+
+.. option:: --method=URI
+
+ Specify the PMI method to use, where the scheme portion of the URI specifies
+ a plugin and the path portion specifies plugin-specific options. The
+ builtin plugins are
+
+ simple
+ Use the simple PMI-1 wire protocol.
+
+ libpmi2[:PATH]
+ :func:`dlopen` ``libpmi2.so`` and use the PMI-2 API, optionally
+ at a specific *PATH*.
+
+ libpmi[:PATH]
+ :func:`dlopen` ``libpmi.so`` and use the PMI-1 API, optionally
+ at a specific *PATH*.
+
+ single
+ Become a singleton.
+
+.. option:: --libpmi-noflux
+
+ Fail if the libpmi or libpmi2 methods find the Flux ``libpmi.so``.
+
+.. option:: --libpmi2-cray
+
+ Force the libpmi2 Cray workarounds to be enabled for testing. Normally
+ they are enabled only if a heuristic detects that Cray libpmi2 is in use.
+ The workarounds are
+
+ - Encode all KVS values with base64.
+ - Immediately fail an attempt to fetch any KVS with a ``flux.`` prefix.
+
+COMMANDS
+========
+
+barrier
+-------
+
+.. program:: flux pmi barrier
+
+:program:`flux pmi barrier` does the following:
+
+ #. Execute PMI barrier
+ #. Execute PMI barrier
+ #. Print elapsed time of (2)
+
+.. option:: --count=N
+
+ Execute N barrier (step 2) operations (default 1).
+
+.. option:: --abort=RANK
+
+ Instead of entering the barrier, arrange for RANK to call the PMI
+ abort function.
+
+exchange
+--------
+
+.. program:: flux pmi exchange
+
+:program:`flux pmi exchange` does the following:
+
+ #. Execute PMI barrier
+ #. Put rank specific key to PMI KVS
+ #. Execute PMI barrier
+ #. Get rank specific key from PMI KVS for all other ranks
+ #. Execute PMI barrier
+ #. Print elapsed time of (2-5)
+
+.. option:: --count=N
+
+ Execute N exchange (step 2-5) operations (default 1).
+
+get
+---
+
+.. program:: flux pmi get
+
+:program:`flux pmi get` fetches a pre-set key from the PMI KVS.
+
+.. option:: --ranks=RANKS
+
+ Print the value on specified *RANKS*, an RFC 22 idset or ``all`` (default 0).
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_13`
+
+
+SEE ALSO
+========
+
+:man7:`flux-broker-attributes`
diff --git a/doc/man1/flux-proxy.adoc b/doc/man1/flux-proxy.adoc
deleted file mode 100644
index 8ae1fb0ec420..000000000000
--- a/doc/man1/flux-proxy.adoc
+++ /dev/null
@@ -1,58 +0,0 @@
-// flux-help-command: proxy
-// flux-help-description: Create proxy environment for Flux instance
-FLUX-PROXY(1)
-=============
-:doctype: manpage
-
-
-NAME
-----
-flux-proxy - create proxy environment for Flux instance
-
-
-SYNOPSIS
---------
-*flux* *proxy* URI [command [args...]]
-
-
-DESCRIPTION
------------
-*flux proxy* connects to the Flux instance identified by _URI_,
-then spawns a shell with FLUX_URI pointing to a local:// socket
-managed by the proxy program. As long as the shell is running,
-the proxy program routes messages between the instance and the
-local:// socket. Once the shell terminates, the proxy program
-terminates and removes the socket.
-
-The purpose of *flux proxy* is to allow a connection to be reused,
-for example where connection establishment has high latency or
-requires authentication.
-
-EXAMPLES
---------
-
-Connect to a job running on the localhost which has a FLUX_URI
-of local:///tmp/flux-123456-abcdef/0/local and spawn an interactive
-shell:
-
- $ flux proxy local:///tmp/flux-123456-abcdef/0/local
-
-Connect to the same job remotely on host foo.com:
-
- $ flux proxy ssh://foo.com/tmp/flux-123456-abcdef/0/local
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
diff --git a/doc/man1/flux-proxy.rst b/doc/man1/flux-proxy.rst
new file mode 100644
index 000000000000..bcc19e2b62e4
--- /dev/null
+++ b/doc/man1/flux-proxy.rst
@@ -0,0 +1,119 @@
+.. flux-help-command: proxy
+.. flux-help-description: proxy connections to Flux jobs and instances
+.. flux-help-section: jobs
+
+=============
+flux-proxy(1)
+=============
+
+
+SYNOPSIS
+========
+
+**flux** **proxy** [*OPTIONS*] TARGET [command [args...]]
+
+DESCRIPTION
+===========
+
+.. program:: flux proxy
+
+:program:`flux proxy` connects to the Flux instance identified by *TARGET*,
+then spawns a shell with :envvar:`FLUX_URI` pointing to a local:// socket
+managed by the proxy program. As long as the shell is running,
+the proxy program routes messages between the instance and the
+local:// socket. Once the shell terminates, the proxy program
+terminates and removes the socket.
+
+The *TARGET* argument is a URI which can be resolved by ``flux uri``,
+including a Flux jobid, a fully-resolved native ``ssh`` or ``local``
+URI, or a resolvable URI with a scheme supported by a ``flux uri``
+plugin. See :man1:`flux-uri` for details.
+
+If the connection to the Flux instance is lost, for example when the
+target instance terminates, :program:`flux proxy` will emit an error message,
+send ``SIGHUP`` and ``SIGCONT`` to the spawned shell or other process,
+and wait for it to terminate before exiting. The delivery of signals
+can be disabled with the :option:`--nohup` option, but be aware that Flux
+commands running under a **flux proxy** which has lost its connection
+will likely result in errors.
+
+The purpose of :program:`flux proxy` is to allow a connection to be reused,
+for example where connection establishment has high latency or
+requires authentication.
+
+
+OPTIONS
+=======
+
+.. option:: -f, --force
+
+ Allow the proxy command to connect to a broker running a different
+ version of Flux with a warning message instead of a fatal error.
+
+.. option:: -n, --nohup
+
+ When an error occurs in the proxy connection, :program:`flux proxy` will
+ normally shut down the proxy and send ``SIGHUP`` and ``SIGCONT`` to
+ the spawned shell or command. If the :option:`--nohup` option is used,
+ the ``SIGHUP`` and ``SIGCONT`` signals will not be sent.
+ :program:`flux proxy` will still wait for the spawned shell or command to
+ exit before terminating to avoid having the child process reparented
+ and possibly lose its controlling tty.
+
+.. option:: --reconnect
+
+ If broker communication fails, drop the current connection and try to
+ reconnect every 2 seconds until the connection succeeds. Any event
+ subscriptions and service registrations that were made on behalf of
+ clients are re-established, and in-flight RPCs receive an ECONNRESET
+ error responses.
+
+
+EXAMPLES
+========
+
+Connect to a job running on the localhost which has a :envvar:`FLUX_URI`
+of ``local:///tmp/flux-123456-abcdef/0/local`` and spawn an interactive
+shell:
+
+::
+
+ $ flux proxy local:///tmp/flux-123456-abcdef/0/local
+
+Connect to the same job remotely on host foo.com:
+
+::
+
+ $ flux proxy ssh://foo.com/tmp/flux-123456-abcdef/0/local
+
+Connect to a Flux instance running as job ÆQBfmbm in the current instance:
+
+::
+
+ $ flux proxy ÆQBfmbm
+
+or
+
+::
+
+ $ flux proxy jobid:ÆQBfmbm
+
+
+Connect to a Flux instance running as job ÆQ8ho35 in ÆQBfmbm
+
+::
+
+ $ flux proxy jobid:ÆQBfmbm/ÆQ8ho35
+
+
+Connect to a Flux instance started in Slurm job 1234
+
+::
+
+ $ flux proxy slurm:1234
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
diff --git a/doc/man1/flux-pstree.rst b/doc/man1/flux-pstree.rst
new file mode 100644
index 000000000000..ed1db274933d
--- /dev/null
+++ b/doc/man1/flux-pstree.rst
@@ -0,0 +1,252 @@
+.. flux-help-include: true
+.. flux-help-section: jobs
+
+==============
+flux-pstree(1)
+==============
+
+
+SYNOPSIS
+========
+
+**flux** **pstree** [*OPTIONS*] [JOBID ...]
+
+DESCRIPTION
+===========
+
+.. program:: flux pstree
+
+:program:`flux pstree` displays a tree of running jobs by job name, similar to
+what the :linux:man1:`pstree` command does for system processes.
+
+Like :command:`pstree`, identical leaves of the job tree are combined, which
+results in a more compact output when many jobs within a Flux instance
+share the same job name.
+
+The :program:`flux pstree` command supports custom labels for jobs, including
+separately labeling parent jobs, using the same format string syntax
+supported by :man1:`flux-jobs`.
+
+The command lists actively running jobs by default, but a :option:`--all`
+option lists all jobs in all states for the current user. In the case
+that :option:`-all` is used, the job labels will automatically be amended to
+include the job status (i.e. ``{name}:{status_abbrev}``), though this
+can be overridden on the command line.
+
+The :program:`flux pstree` command additionally supports listing extended
+job information before the tree display with the :option:`--extended`,
+:option:`--details=NAME`, or :option:`--detail-format=FORMAT` options, e.g.
+
+::
+
+ $ flux pstree -x
+ JOBID USER ST NTASKS NNODES RUNTIME
+ ÆJqUHUCzX9 user1 R 2 2 10.68s flux
+ Æe1j54L user1 R 1 1 8.539s âââ flux
+ ÆuusNLo user1 R 1 1 5.729s â âââ sleep
+ ÆutPP4T user1 R 1 1 5.731s â âââ sleep
+ Æe1j54K user1 R 1 1 8.539s âââ flux
+ Æ2MYrwzf user1 R 1 1 4.736s âââ sleep
+
+Several detail formats are available via the :option:`-d, --details=NAME`
+option, including progress, resources, and stats. For example, the
+``progress`` display attempts to show the overall progress and
+utilization of all Flux instances in a hierarchy by displaying the
+total number of jobs in that instance (``NJOBS``), the "progress"
+(``PROG`` - inactive/finished jobs divided by total jobs), and
+core and GPU utilization (``CORE%`` and ``GPU%`` - number of used
+resources divided by total available resources):
+
+::
+
+ $ flux pstree --details=progress
+
+ JOBID NTASKS NJOBS PROG CORE% GPU% RUNTIME
+ ÆJqUHUCzX9 2 3 0% 37.5% 0:02:15 flux
+ Æe1j54L 1 1000 23% 100% 0:02:13 âââ flux
+ Æ2HmSnHd 1 0:00:01 â âââ sleep
+ Æ2Hjxo1K 1 0:00:01 â âââ sleep
+ Æe1j54K 1 1000 11.5% 100% 0:02:13 âââ flux
+ Æ2b6cPMS 1 0:00:01 âââ sleep
+
+
+By default, :program:`flux pstree` truncates lines that exceed the current
+value of the ``COLUMNS`` environment variable or the terminal width
+if ``COLUMNS`` is not set. To disable truncation, use the :option:`--long`
+option.
+
+
+By default, the enclosing Flux instance, or root of the tree, is included
+in output, unless extended details are displayed as when any of the
+:option:`--extended`, :option:`--details=NAME` or
+:option:`--detail-format=FORMAT` options are used, or if one or more jobids
+are directly targeted with a ``JOBID`` argument. This behavior can be changed
+via the :option:`--skip-root=[yes|no]` option.
+
+
+OPTIONS
+=======
+
+.. option:: -a, --all
+
+ Include jobs in all states, including inactive jobs.
+ This is shorthand for :option:`--filter=pending,running,inactive`.
+
+.. option:: -c, --count=N
+
+ Limit output to N jobs at every level (default 1000).
+
+.. option:: -f, --filter=STATE|RESULT
+
+ Include jobs with specific job state or result. Multiple states or
+ results can be listed separated by comma. See the :ref:`flux_jobs_job_status`
+ section of the :man1:`flux-jobs` manual for more detail.
+
+.. option:: -l, --long
+
+ Do not truncate long lines at ``COLUMNS`` characters.
+
+.. option:: -p, --parent-ids
+
+ Prepend jobid to parent labels.
+
+.. option:: -L, --level=N
+
+ Only descend *N* levels of the job hierarchy.
+
+.. option:: -x, --extended
+
+ Print extended details before tree output. This is the same as
+ :option:`--details=default`.
+
+.. option:: -d, --detail=NAME
+
+ Select a named extended details format. The list of supported names
+ can be seen in :option:`flux pstree --help` output.
+
+.. option:: -n, --no-header
+
+ For output with extended details, do not print header row.
+
+.. option:: -X, --no-combine
+
+ Typically, identical child jobs that are leaves in the tree display
+ are combined as ``n*[label]``. With this option, the combination of
+ like jobs is disabled.
+
+.. option:: -o, --label=FORMAT
+
+ Specify output format for node labels using Python format strings.
+ Supports all format fields supported by :man1:`flux-jobs`.
+
+.. option:: --parent-label=FORMAT
+
+ Label tree parents with a different format than child jobs.
+
+.. option:: --detail-format=FORMAT
+
+ Specify an explicit details format to display before the tree part.
+ Care should be taken that each line of the format is the same width
+ to ensure that the tree display is rendered correctly (i.e. by judicious
+ use of format field widths, e.g. ``{id.f58:>12}`` instead of just
+ ``{id.f58}``.
+
+.. option:: --skip-root=yes|no
+
+ Explicitly skip (yes) or force (no) display of the enclosing instance,
+ or root of the tree, in output.
+
+.. option:: -C, --compact
+
+ Use compact tree connectors. Usefully for deep hierarchies.
+
+.. option:: --ascii
+
+ Use ascii tree connectors.
+
+
+EXAMPLES
+========
+
+The default output of :program:`flux pstree` shows all running jobs for the
+current user by name, including any running sub-jobs. If there are
+currently no running jobs for the current user, only the enclosing
+instance is displayed as a ``.``, to indicate the root of the tree:
+
+::
+
+ $ flux pstree
+ .
+
+
+If there is a running job, it is displayed under the root instance,
+and includes all child jobs. Identical children are combined:
+
+::
+
+ $ flux pstree
+ .
+ âââ flux
+ âââ flux
+ â âââ 2*[sleep]
+ âââ flux
+ âââ sleep
+
+
+Extra information can be added to parents, which are instances of
+flux. For example, summary job stats can be easily added:
+
+::
+
+ $ flux pstree --skip-root=yes --parent-label='{name} {instance.stats}'
+ flux PD:1 R:2 CD:0 F:0
+ âââ flux PD:592 R:2 CD:406 F:0
+ â âââ 2*[sleep]
+ âââ flux PD:794 R:1 CD:205 F:0
+ âââ sleep
+
+Or utilization:
+
+::
+
+ $ flux pstree --skip-root=yes \
+ --parent-label='cores={instance.resources.all.ncores} {instance.utilization!P}' \
+ cores=8 37.5%
+ âââ cores=2 100%
+ â âââ 2*[sleep]
+ âââ cores=1 100%
+
+Displaying jobs in all states automatically adds the job *status* to the
+display, which offers a compact representation of the state of jobs
+throughout a hierarchy:
+
+::
+
+ $ flux pstree -a
+ .
+ âââ flux
+ â âââ flux:PD
+ â âââ flux
+ â â âââ 824*[sleep:PD]
+ â â âââ 2*[sleep:R]
+ â â âââ 174*[sleep:CD]
+ â âââ flux
+ â âââ 914*[sleep:PD]
+ â âââ sleep:R
+ â âââ 85*[sleep:CD]
+ âââ flux:CA
+ âââ 36*[flux:CD]
+ âââ hostname:CA
+ âââ hostname:CD
+
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+SEE ALSO
+========
+
+:man1:`flux-jobs`
diff --git a/doc/man1/flux-queue.rst b/doc/man1/flux-queue.rst
new file mode 100644
index 000000000000..8584eac9a6b1
--- /dev/null
+++ b/doc/man1/flux-queue.rst
@@ -0,0 +1,294 @@
+.. flux-help-description: list and manipulate flux queues
+.. flux-help-section: instance
+
+=============
+flux-queue(1)
+=============
+
+
+SYNOPSIS
+========
+
+| **flux** **queue** **list** [-n] [-o FORMAT]
+| **flux** **queue** **status** [*-q* *NAME* | *-a*] [*-v*]
+
+| **flux** **queue** **disable** [*-q* *NAME* | *-a*] [*-v*] [*--quiet*] [*--nocheckpoint*] *reason*
+| **flux** **queue** **enable** [*-q* *NAME* | *-a*] [*-v*] [*--quiet*]
+
+| **flux** **queue** **stop** [*-q* *NAME* | *-a*] [*-v*] [*--quiet*] [*--nocheckpoint*] *reason*
+| **flux** **queue** **start** [*-q* *NAME* | *-a*] [*-v*] [*--quiet*]
+
+| **flux** **queue** **drain** [*--timeout=DURATION*]
+| **flux** **queue** **idle** [*--timeout=DURATION*]
+
+
+DESCRIPTION
+===========
+
+.. program:: flux queue
+
+The :program:`flux queue` command operates on Flux job queue(s).
+
+By default, Flux has one anonymous queue. Multiple named queues may be
+configured - see :man5:`flux-config-queues`.
+
+COMMANDS
+========
+
+:program:`flux queue` has the following subcommands:
+
+list
+----
+
+.. program:: flux queue list
+
+List queue status, defaults, and limits.
+
+.. option:: -q, --queue=QUEUE,...
+
+ Limit output to specified queues
+
+.. option:: -n, --no-header
+
+ Do not output column headers in ``list`` output.
+
+.. option:: -o, --format=FORMAT
+
+ Specify output format in ``list`` using Python's string format syntax.
+ See `OUTPUT FORMAT`_ below for field names.
+
+status
+------
+
+.. program:: flux queue status
+
+Report the current queue status.
+
+.. option:: -q, --queue=NAME
+
+ Select a queue by name.
+
+.. option:: -v, --verbose
+
+ Display more detail about internal job manager state.
+
+disable
+-------
+
+.. program:: flux queue disable
+
+Prevent jobs from being submitted to the queue, with a reason that is
+shown to submitting users.
+
+.. option:: -q, --queue=NAME
+
+ Select a queue by name.
+
+.. option:: -a, --all
+
+ Select all queues.
+
+.. option:: -v, --verbose
+
+ Display more detail about internal job manager state.
+
+.. option:: --quiet
+
+ Display only errors.
+
+.. option:: --nocheckpoint
+
+ Do not preserve the new queue stop state across a Flux instance restart.
+
+enable
+------
+
+.. program:: flux queue enable
+
+Allow jobs to be submitted to the queue.
+
+.. option:: -q, --queue=NAME
+
+ Select a queue by name.
+
+.. option:: -a, --all
+
+ Select all queues.
+
+.. option:: -v, --verbose
+
+ Display more detail about internal job manager state.
+
+.. option:: --quiet
+
+ Display only errors.
+
+stop
+----
+
+.. program:: flux queue stop
+
+Stop allocating resources to jobs. Pending jobs remain enqueued, and
+running jobs continue to run, but no new jobs are allocated
+resources.
+
+.. option:: -q, --queue=NAME
+
+ Select a queue by name.
+
+.. option:: -a, --all
+
+ Select all queues.
+
+.. option:: -v, --verbose
+
+ Display more detail about internal job manager state.
+
+.. option:: --quiet
+
+ Display only errors.
+
+.. option:: --nocheckpoint
+
+ Do not preserve the new queue stop state across a Flux instance restart.
+
+start
+-----
+
+.. program:: flux queue start
+
+Start allocating resources to jobs.
+
+.. option:: -q, --queue=NAME
+
+ Select a queue by name.
+
+.. option:: -a, --all
+
+ Select all queues.
+
+.. option:: -v, --verbose
+
+ Display more detail about internal job manager state.
+
+.. option:: --quiet
+
+ Display only errors.
+
+drain
+-----
+
+.. program:: flux queue drain
+
+Block until all queues become empty. It is sometimes useful to run after
+:program:`flux queue disable`, to wait until the system is quiescent and can
+be taken down for maintenance.
+
+.. option:: --timeout=FSD
+
+ Limit the time that the command` will block.
+
+idle
+----
+
+.. program:: flux queue idle
+
+Block until all queues become `idle` (no jobs in RUN or CLEANUP state,
+and no outstanding alloc requests to the scheduler). It may be useful to run
+after :program:`flux queue stop` to wait until the scheduler and execution
+system are quiescent before maintenance involving them.
+
+.. option:: --timeout=FSD
+
+ Limit the time that the command` will block.
+
+
+OUTPUT FORMAT
+=============
+
+The :option:`flux queue list --format` option can be used to specify an
+output format using Python's string format syntax or a defined format by
+name. For a list of built-in and configured formats use :option:`-o help`.
+An alternate default format can be set via the
+:envvar:`FLUX_QUEUE_LIST_FORMAT_DEFAULT` environment variable.
+A configuration snippet for an existing named format may be
+generated with :option:`--format=get-config=NAME`. See :man1:`flux-jobs`
+*OUTPUT FORMAT* section for a detailed description of this syntax.
+
+The following field names can be specified:
+
+**queue**
+ queue name
+
+**queuem**
+ queue name, but default queue is marked up with an asterisk
+
+**submission**
+ Description of queue submission status: ``enabled`` or ``disabled``
+
+**scheduling**
+ Description of queue scheduling status: ``started`` or ``stopped``
+
+**enabled**
+ Single character submission status: ``â`` if enabled, ``â`` if disabled.
+
+**started**
+ Single character scheduling status: ``â`` if started, ``â`` if stopped.
+
+**enabled.ascii**
+ Single character submission status: ``y`` if enabled, ``n`` if disabled.
+
+**started.ascii**
+ Single character scheduling status: ``y`` if started, ``n`` if stopped.
+
+**defaults.timelimit**
+ default timelimit for jobs submitted to the queue
+
+**limits.timelimit**
+ max timelimit for jobs submitted to the queue
+
+**limits.range.nnodes**
+ range of nodes that can be requested for this queue
+
+**limits.range.ncores**
+ range of cores that can be requested for this queue
+
+**limits.range.ngpus**
+ range of gpus that can be requested for this queue
+
+**limits.min.nnodes**
+ minimum number of nodes that must be requested for this queue
+
+**limits.max.nnodes**
+ maximum number of nodes that can be requested for this queue
+
+**limits.min.ncores**
+ minimum number of cores that must be requested for this queue
+
+**limits.max.ncores**
+ maximum number of cores that can be requested for this queue
+
+**limits.min.ngpus**
+ minimum number of gpus that must be requested for this queue
+
+**limits.max.ngpus**
+ maximum number of gpus that can be requested for this queue
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+| :doc:`rfc:spec_23`
+| :doc:`rfc:spec_33`
+
+
+SEE ALSO
+========
+
+:man1:`flux-jobs`, :man1:`flux-submit`
diff --git a/doc/man1/flux-resource.rst b/doc/man1/flux-resource.rst
new file mode 100644
index 000000000000..fab5c39a6b94
--- /dev/null
+++ b/doc/man1/flux-resource.rst
@@ -0,0 +1,522 @@
+.. flux-help-include: true
+.. flux-help-section: instance
+
+================
+flux-resource(1)
+================
+
+
+SYNOPSIS
+========
+
+| **flux** **resource** **list** [*-n*] [*-o* *FORMAT*] [*-s* *STATES*] [*-q* *QUEUE*] [*-i* *TARGETS*]
+| **flux** **resource** **info** [*-s* *STATES*] [*-q* *QUEUE*] [*-i* *TARGETS*]
+| **flux** **resource** **R** [*-s* *STATES*] [*-q* *QUEUE*] [*-i* *TARGETS*]
+
+| **flux** **resource** **status** [*-n*] [*-o* *FORMAT*] [*-s* *STATES*] [*-q* *QUEUE*] [*-i* *TARGETS*]
+
+| **flux** **resource** **drain** [*-n*] [*-o* *FORMAT*] [*-i* *TARGETS*]
+| **flux** **resource** **drain** [*-f*] [*-u*] [*targets*] [*reason*]
+| **flux** **resource** **undrain** [*-f*] *targets*
+
+| **flux** **resource** **reload** [-f] [--xml] *path*
+
+| **flux** **resource** **acquire-mute**
+
+DESCRIPTION
+===========
+
+.. program:: flux resource
+
+:program:`flux resource` lists and manipulates Flux resources. The resource
+inventory is maintained and monitored by the resource service. The scheduler
+acquires a subset of resources from the resource service to allocate to jobs,
+and relies on the resource service to inform it of status changes that affect
+the usability of resources by jobs as described in RFC 27.
+
+The :program:`flux resource list` subcommand queries the resource module
+for the scheduler view of resources, including allocated/free status.
+
+The other :program:`flux resource` subcommands operate on the resource service
+and are primarily of interest to system administrators of a Flux system
+instance. For example, they can show whether or not a node is booted, and may
+be used to administratively drain and undrain nodes.
+
+A few notes on drained nodes:
+
+- While a node is drained, the scheduler will not allocate it to jobs.
+- The act of draining a node does not affect running jobs.
+- When an instance is restarted, drained nodes remain drained.
+- The scheduler may determine that a job request is *feasible* if the total
+ resource set, including drained nodes, would allow it to run.
+- In :program:`flux resource status` and :program:`flux resource drain`, the
+ drain state of a node will be presented as "drained" if the node has no job
+ allocations, and "draining" if there are still jobs running on the node.
+- If a node is drained and offline, then "drained*" will be displayed.
+
+Some further background on resource service operation may be found in the
+`RESOURCE INVENTORY`_ section below.
+
+
+COMMANDS
+========
+
+list
+----
+
+.. program:: flux resource list
+
+Show the scheduler view of resources.
+
+In the scheduler view, excluded resources are always omitted, and
+unavailable resources are shown in the "down" state regardless of the
+reason (drained, offline, torpid, etc). Valid states in the scheduler view are:
+
+up
+ Available for use.
+
+down
+ Unavailable for use.
+
+allocated
+ Allocated to jobs.
+
+free
+ Not allocated to jobs.
+
+all
+ Wildcard matching all resources.
+
+.. option:: -s, --states=STATE,...
+
+ Restrict displayed resource states to a comma separated list of
+ the states listed above.
+
+ If unspecified, :option:`free,allocated,down` is used.
+
+.. option:: -q, --queue=QUEUE,...
+
+ Filter results to only include resources in the specified *QUEUE*. Multiple
+ queues may be separated by a comma.
+
+.. option:: -i, --include=TARGETS
+
+ Filter results to only include resources matching *TARGETS*, which may be
+ specified either as an idset of broker ranks or list of hosts or nodes in
+ hostlist form. It is not an error to specify ranks, nodes, or hosts which
+ do not exist.
+
+.. option:: --skip-empty
+
+ Skip lines with empty resource sets in output. This is the default when
+ `-i, --include` is used.
+
+.. options:: --no-skip-empty
+
+ Do not skip empty resource sets in output, even with `-i, --include`.
+
+.. option:: -o, --format=FORMAT
+
+ Customize the output format (See the `OUTPUT FORMAT`_ section below).
+
+.. option:: -n, --no-header
+
+ Suppress header from output,
+
+info
+----
+
+.. program:: flux resource info
+
+Show a brief, single line summary of scheduler view of resources, for
+example::
+
+ 8 Nodes, 32 Cores, 0 GPUs
+
+.. option:: -s, --states=STATE,...
+
+ Limit the output to specified resource states as described above for
+ the `list`_ command.
+
+ If unspecified, :option:`all` is used.
+
+.. option:: -q, --queue=QUEUE,...
+
+ Filter results to only include resources in the specified *QUEUE*. Multiple
+ queues may be separated by a comma.
+
+.. option:: -i, --include=TARGETS
+
+ Filter results to only include resources matching *TARGETS*, which may be
+ specified either as an idset of broker ranks or list of hosts or nodes in
+ hostlist form. It is not an error to specify ranks, nodes, or hosts which
+ do not exist.
+
+R
+-
+
+.. program:: flux resource R
+
+Emit an RFC 20 Resource Set based on the scheduler view of resources.
+
+.. option:: -s, --states=STATE,...
+
+ Limit the output to specified resource states as described above for
+ the `list`_ command.
+
+ If unspecified, :option:`all` is used.
+
+.. option:: -q, --queue=QUEUE,...
+
+ Filter results to only include resources in the specified *QUEUE*. Multiple
+ queues may be separated by a comma.
+
+.. option:: -i, --include=TARGETS
+
+ Filter results to only include resources matching *TARGETS*, which may be
+ specified either as an idset of broker ranks or list of hosts or nodes in
+ hostlist form. It is not an error to specify ranks, nodes, or hosts which
+ do not exist.
+
+status
+------
+
+.. program:: flux resource status
+
+Show system view of resources. Valid states in the system view are:
+
+avail
+ available for scheduling when up. This includes all nodes that are
+ not excluded, drained, or torpid.
+
+exclude
+ excluded by configuration
+
+draining
+ drained but still allocated
+
+drained
+ drained and unallocated
+
+drain
+ shorthand for :option:`drained,draining`
+
+allocated
+ node is currently allocated to a job or housekeeping
+
+torpid
+ node has been unresponsive for a period of time and is temporarily
+ unavailable for scheduling
+
+housekeeping
+ node is currently running housekeeping
+
+offline
+ node has not joined the Flux instance (e.g. turned off or has not
+ started the flux broker).
+
+online
+ node has joined the Flux instance
+
+:program:`flux resource status` displays a line of output for each set of
+resources that share a state and online/offline state.
+
+.. note::
+ :program:`flux resource status` queries both the administrative and
+ scheduler view of resources to identify resources that are available,
+ excluded by configuration, torpid, administratively drained or draining,
+ or currently executing housekeeping.
+
+.. option:: -s, --states=STATE,...
+
+ Restrict the set of resource states a comma-separated list.
+
+ If unspecified, :option:`avail,exclude,draining,drained,torpid,housekeeping`
+ is used.
+
+
+.. option:: -q, --queue=QUEUE,...
+
+ Filter results to only include resources in the specified *QUEUE*. Multiple
+ queues may be separated by a comma.
+
+.. option:: -i, --include=TARGETS
+
+ Filter results to only include resources matching *TARGETS*, which may be
+ specified either as an idset of broker ranks or list of hosts or nodes in
+ hostlist form. It is not an error to specify ranks, nodes, or hosts which
+ do not exist.
+
+.. option:: -o, --format=FORMAT
+
+ Customize output formatting. See the `OUTPUT FORMAT`_ section below for
+ details.
+
+.. option:: -n,--no-header
+
+ Suppress header from output,
+
+.. option:: --skip-empty
+
+ Force suppression of empty lines.
+
+ Normally, :program:`flux resource status` skips lines with no resources,
+ unless the :option:`-s, --states` option is used.
+
+drain
+-----
+
+.. program:: flux resource drain
+
+If specified without *targets*, list the drained nodes. In this mode, the
+following options are available:
+
+.. option:: -o, --format=FORMAT
+
+ Customize output formatting. See the `OUTPUT FORMAT`_ section below for
+ details.
+
+.. option:: -n,--no-header
+
+ Suppress header from output,
+
+.. option:: -q, --queue=QUEUE,...
+
+ Filter results to only include resources in the specified *QUEUE*. Multiple
+ queues may be separated by a comma.
+
+.. option:: -i, --include=TARGETS
+
+ Filter results to only include resources matching *TARGETS*, which may be
+ specified either as an idset of broker ranks or list of hosts or nodes in
+ hostlist form. It is not an error to specify ranks, nodes, or hosts which
+ do not exist.
+
+If specified with *targets* (IDSET or HOSTLIST), drain the specified nodes.
+Any remaining free arguments are recorded as a reason for the drain event.
+By default, :program:`flux resource drain` fails if any of the *targets*
+are already drained.
+
+Resources cannot be both excluded and drained, so
+:program:`flux resource drain` will also fail if any *targets* are
+currently excluded by configuration. There is no option to force an
+excluded node into the drain state.
+
+This command, when run with arguments, is restricted to the Flux instance
+owner.
+
+.. option:: -f, --force
+
+ If any of *targets* are already drained, do not fail. Overwrite the
+ original drain reason. When :option:`--force` is specified twice,
+ the original drain timestamp is also overwritten.
+
+.. option:: -u, --update
+
+ If any of *targets* are already drained, do not fail and do not overwrite
+ the existing drain reason or timestamp.
+
+undrain
+-------
+
+.. program:: flux resource undrain
+
+Undrain the nodes specified by the *targets* argument (IDSET or HOSTLIST).
+
+This command is restricted to the Flux instance owner.
+
+.. option:: -f, --force
+
+ Do not fail if any of the *targets* are not drained.
+
+reload
+------
+
+.. program:: flux resource reload
+
+Reload the resource inventory from *path*. By default, *path* refers to a
+file in RFC 20 format.
+
+This command is primarily used in test.
+
+.. option:: -x, --xml
+
+ Interpret *path* as a directory of hwloc ``.xml`` files.
+
+.. option:: -f, --force
+
+ Do not fail if resource contain invalid ranks.
+
+acquire-mute
+------------
+
+.. program:: flux resource acquire-mute
+
+Tell the resource module to stop sending RFC 28 ``resource.acquire`` responses
+to the scheduler. This is used during Flux instance shutdown to avoid asking
+the scheduler to needlessly process OFFLINE updates.
+
+OUTPUT FORMAT
+=============
+
+The :option:`--format` option can be used to specify an output format using
+Python's string format syntax or a defined format by name. For a list of
+built-in and configured formats use :option:`-o help`. An alternate default
+format can be set via the :envvar:`FLUX_RESOURCE_STATUS_FORMAT_DEFAULT`,
+:envvar:`FLUX_RESOURCE_DRAIN_FORMAT_DEFAULT`, and
+:envvar:`FLUX_RESOURCE_LIST_FORMAT_DEFAULT` environment variables (for
+:program:`flux resource status`, :program:`flux resource drain`, and
+:program:`flux resource list` respectively). A configuration snippet for an
+existing named format may be generated with :option:`--format=get-config=NAME`.
+See :man1:`flux-jobs` :ref:`flux_jobs_output_format` section for a detailed
+description of this syntax.
+
+Resources are combined into a single line of output when possible depending on
+the supplied output format. Resource counts are not included in the
+determination of uniqueness. Therefore, certain output formats will alter the
+number of lines of output. For example:
+
+::
+
+ $ flux resource list -no {nnodes}
+
+Would simply output a single of output containing the total number of nodes.
+The actual state of the nodes would not matter in the output.
+
+The following field names can be specified for the **status** and **drain**
+subcommands:
+
+**state**
+ State of node(s): "avail", "exclude", "drain", "draining", "drained",
+ "torpid", "allocated". If the set of resources is offline, an asterisk
+ suffix is appended to the state, e.g. "avail*".
+
+**statex**
+ Like **state**, but exclude the asterisk for offline resources.
+
+**status**
+ Current online/offline status of nodes(s): "online", "offline"
+
+**up**
+ Displays a *â* if the node is online, or *â* if offline. An ascii *y*
+ or *n* may be used instead with **up.ascii**.
+
+**nnodes**
+ number of nodes
+
+**ranks**
+ ranks of nodes
+
+**nodelist**
+ node names
+
+**timestamp**
+ If node(s) in drain/draining/drained state, timestamp of node(s)
+ set to drain.
+
+**reason**
+ If node(s) in drain/draining/drained state, reason node(s) set to
+ drain.
+
+The following field names can be specified for the **list** subcommand:
+
+**state**
+ State of node(s): "up", "down", "allocated", "free", "all"
+
+**queue**
+ queue(s) associated with resources.
+
+**properties**
+ Properties associated with resources.
+
+**propertiesx**
+ Properties associated with resources, but with queue names removed.
+
+**nnodes**
+ number of nodes
+
+**ncores**
+ number of cores
+
+**ngpus**
+ number of gpus
+
+**ranks**
+ ranks of nodes
+
+**nodelist**
+ node names
+
+**rlist**
+ Short form string of all resources.
+
+
+CONFIGURATION
+=============
+
+Similar to :man1:`flux-jobs`, the :program:`flux resource` command supports
+loading a set of config files for customizing utility output formats. Currently
+this can be used to register named format strings for the ``status``,
+``list``, and ``drain`` subcommands.
+
+Configuration for each :program:`flux resource` subcommand is defined in a
+separate table, so to add a new format ``myformat`` for ``flux resource list``,
+the following config file could be used::
+
+ # $HOME/.config/flux/flux-resource.toml
+ [list.formats.myformat]
+ description = "My flux resource list format"
+ format = "{state} {nodelist}"
+
+See :man1:`flux-jobs` :ref:`flux_jobs_configuration` section for more
+information about the order of precedence for loading these config files.
+
+RESOURCE INVENTORY
+==================
+
+The Flux instance's inventory of resources is managed by the resource service,
+which determines the set of available resources through one of three
+mechanisms:
+
+configuration
+ Resources are read from a config file in RFC 20 (R version 1) format.
+ This mechanism is typically used in a system instance of Flux.
+
+enclosing instance
+ Resources are assigned by the enclosing Flux instance. The assigned
+ resources are read from the job's ``R`` key in the enclosing instance KVS.
+
+dynamic discovery
+ Resources are aggregated from the set of resources reported by hwloc
+ on each broker.
+
+Once the inventory has been determined, it is stored the KVS ``resource.R``
+key, in RFC 20 (R version 1) format.
+
+Events that affect the availability of resources and should persist across
+a Flux restart are posted to the KVS *resource.eventlog*. Such events include:
+
+resource-define
+ The instance resource set is known (posted each time the resource module
+ is loaded).
+
+drain
+ One or more nodes are administratively removed from scheduling.
+
+undrain
+ One or more nodes are no longer drained.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+| :doc:`rfc:spec_20`
+| :doc:`rfc:spec_22`
+| :doc:`rfc:spec_27`
+| :doc:`rfc:spec_29`
diff --git a/doc/man1/flux-restore.rst b/doc/man1/flux-restore.rst
new file mode 100644
index 000000000000..11c24439dd2c
--- /dev/null
+++ b/doc/man1/flux-restore.rst
@@ -0,0 +1,88 @@
+===============
+flux-restore(1)
+===============
+
+
+SYNOPSIS
+========
+
+**flux** **restore** [*OPTIONS*] *INFILE*
+
+
+DESCRIPTION
+===========
+
+.. program:: flux restore
+
+The :program:`flux restore` command reads a KVS snapshot from a portable
+archive format, usually written by :man1:`flux-dump`.
+
+The archive source may be specified as a file path or *-* for standard input.
+The format of the archive may be any of the formats supported by
+:linux:man3:`libarchive` and is determined on the fly based on the archive
+content.
+
+The snapshot may be restored to a KVS key if :option:`--key=NAME` is used and
+the KVS service is running, or as a checkpoint in the content backing store
+if :option:`--checkpoint` is used, without the KVS running. One of those two
+options is required.
+
+
+OPTIONS
+=======
+
+.. option:: -h, --help
+
+ Summarize available options.
+
+.. option:: -v, --verbose
+
+ List keys on stderr as they are restored instead of a periodic count of
+ restored keys.
+
+.. option:: -q, --quiet
+
+ Don't show a periodic count of restored keys on stderr.
+
+.. option:: --checkpoint
+
+ After restoring the archived content, write the final root blobref
+ to the KVS checkpoint area in the content backing store. The checkpoint
+ is used as the initial KVS root when the KVS module is loaded. Unload
+ the KVS module before restoring with this option.
+
+.. option:: --key=NAME
+
+ After restoring the archived content, write the final root blobref
+ to a KVS key, so the key becomes the restored root directory.
+
+.. option:: --no-cache
+
+ Bypass the broker content cache and interact directly with the backing
+ store. Performance will vary depending on the content of the archive.
+
+.. option:: --size-limit=SIZE
+
+ Skip restoring keys that exceed SIZE bytes (default: no limit). SIZE may
+ be specified as a floating point number with an optional multiplicative
+ suffix k or K=1024, M=1024\*1024, or G=1024\*1024\*1024 (up to
+ ``INT_MAX``).
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_10`
+
+:doc:`rfc:spec_11`
+
+
+SEE ALSO
+========
+
+:man1:`flux-dump`, :man1:`flux-kvs`
diff --git a/doc/man1/flux-run.rst b/doc/man1/flux-run.rst
new file mode 100644
index 000000000000..f440538fc714
--- /dev/null
+++ b/doc/man1/flux-run.rst
@@ -0,0 +1,167 @@
+.. flux-help-include: true
+.. flux-help-section: submission
+
+===========
+flux-run(1)
+===========
+
+
+SYNOPSIS
+========
+
+**flux** **run** [OPTIONS] [*--ntasks=N*] COMMAND...
+
+
+DESCRIPTION
+===========
+
+.. program:: flux run
+
+:program:`flux run` submits a job to run interactively under Flux, blocking
+until the job has completed. The job consists of *N* copies of COMMAND
+launched together as a parallel job.
+
+If :option:`--ntasks` is unspecified, a value of *N=1* is assumed.
+
+The available OPTIONS are detailed below.
+
+JOB PARAMETERS
+==============
+
+These commands accept only the simplest parameters for expressing
+the size of the parallel program and the geometry of its task slots:
+
+Common resource options
+-----------------------
+
+These commands take the following common resource allocation options:
+
+.. include:: common/job-param-common.rst
+
+Per-task options
+----------------
+
+:man1:`flux-run`, :man1:`flux-submit` and :man1:`flux-bulksubmit` take two
+sets of mutually exclusive options to specify the size of the job request.
+The most common form uses the total number of tasks to run along with
+the amount of resources required per task to specify the resources for
+the entire job:
+
+.. include:: common/job-param-pertask.rst
+
+Per-resource options
+--------------------
+
+The second set of options allows an amount of resources to be specified
+with the number of tasks per core or node set on the command line. It is
+an error to specify any of these options when using any per-task option
+listed above:
+
+.. include:: common/job-param-perres.rst
+
+Additional job options
+----------------------
+
+These commands also take following job parameters:
+
+.. include:: common/job-param-additional.rst
+
+STANDARD I/O
+============
+
+By default, task stdout and stderr streams are redirected to the
+KVS, where they may be accessed with the ``flux job attach`` command.
+
+In addition, :man1:`flux-run` processes standard I/O in real time,
+emitting the job's I/O to its stdout and stderr.
+
+.. include:: common/job-standard-io.rst
+
+CONSTRAINTS
+===========
+
+.. include:: common/job-constraints.rst
+
+DEPENDENCIES
+============
+
+.. include:: common/job-dependencies.rst
+
+ENVIRONMENT
+===========
+
+By default, these commands duplicate the current environment when submitting
+jobs. However, a set of environment manipulation options are provided to
+give fine control over the requested environment submitted with the job.
+
+.. include:: common/job-environment.rst
+
+ENV RULES
+---------
+
+.. include:: common/job-env-rules.rst
+
+PROCESS RESOURCE LIMITS
+=======================
+
+By default these commands propagate some common resource limits (as described
+in :linux:man2:`getrlimit`) to the job by setting the ``rlimit`` job shell
+option in jobspec. The set of resource limits propagated can be controlled
+via the :option:`--rlimit=RULE` option:
+
+.. include:: common/job-process-resource-limits.rst
+
+JOB ENVIRONMENT VARIABLES
+=========================
+
+The job environment is described in more detail in the :man7:`flux-environment`
+:ref:`job_environment` section. A summary of the most commonly used variables
+is provided below:
+
+.. include:: common/job-environment-variables.rst
+
+EXIT STATUS
+===========
+
+The job exit status, normally the largest task exit status, is stored
+in the KVS. If one or more tasks are terminated with a signal,
+the job exit status is 128+signo.
+
+The ``flux-job attach`` command exits with the job exit status.
+
+In addition, :man1:`flux-run` runs until the job completes and exits
+with the job exit status.
+
+OTHER OPTIONS
+=============
+
+.. include:: common/job-other-options.rst
+
+.. include:: common/job-other-run.rst
+
+SHELL OPTIONS
+=============
+
+Some options that affect the parallel runtime environment are provided by the
+Flux shell. These options are described in detail in the
+:ref:`SHELL OPTIONS ` section of :man1:`flux-shell`.
+A list of the most commonly needed options follows.
+
+Usage: :option:`flux run -o NAME[=ARG]`.
+
+.. make :option: references in the included table x-ref to flux-shell(1)
+.. program:: flux shell
+.. include:: common/job-shell-options.rst
+.. program:: flux run
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-submit`, :man1:`flux-alloc`, :man1:`flux-batch`,
+:man1:`flux-bulksubmit`, :man7:`flux-environment`
diff --git a/doc/man1/flux-shell.rst b/doc/man1/flux-shell.rst
new file mode 100644
index 000000000000..b1fa7f165056
--- /dev/null
+++ b/doc/man1/flux-shell.rst
@@ -0,0 +1,680 @@
+==============
+flux-shell(1)
+==============
+
+
+SYNOPSIS
+========
+
+**flux-shell** [*OPTIONS*] *JOBID*
+
+DESCRIPTION
+===========
+
+.. program:: flux shell
+
+:program:`flux shell`, the Flux job shell, is the component of Flux which
+manages the startup and execution of user jobs. :program:`flux shell` runs as
+the job user, reads the jobspec and assigned resource set R for the job from
+the KVS, and using this data determines what local job tasks to execute. While
+job tasks are running, the job shell acts as the interface between the
+Flux instance and the job by handling standard I/O, signals, and finally
+collecting the exit status of tasks as they complete.
+
+The design of the Flux job shell allows customization through a set of
+builtin and runtime loadable shell plugins. These plugins are used to
+handle standard I/O redirection, PMI, CPU and GPU affinity, debugger
+support and more. Details of the :program:`flux shell` plugin capabilities and
+design can be found in the `PLUGINS`_ section below.
+
+:program:`flux shell` also supports configuration via a Lua-based configuration
+file, called the shell ``initrc``, from which shell plugins may be loaded
+or shell options and data examined or set. The :program:`flux shell` initrc may
+even extend the shell itself via simple shell plugins developed directly
+in Lua. See the `SHELL INITRC`_ section below for details of the ``initrc``
+format and features.
+
+OPTIONS
+=======
+
+.. option:: -h, --help
+
+ Summarize available options.
+
+.. option:: --reconnect
+
+ Attempt to reconnect if broker connection is lost.
+
+OPERATION
+=========
+
+When a job has been granted resources by a Flux instance, a
+:program:`flux shell` process is invoked on each broker rank involved in the
+job. The job shell runs as the job user, and will always have
+:envvar:`FLUX_KVS_NAMESPACE` set such that the root of the job shell's
+KVS accesses will be the guest namespace for the job.
+
+Each :program:`flux shell` connects to the local broker, fetches the jobspec
+and resource set **R** for the job from the job-info module, and uses this
+information to plan which tasks to locally execute.
+
+Once the job shell has successfully gathered job information, the
+:program:`flux shell` then goes through the following general steps to manage
+execution of the job:
+
+ * register service endpoint specific to the job and userid,
+ typically ``-shell-``
+ * load the system default ``initrc.lua``
+ (``$sysconfdir/flux/shell/initrc.lua``), unless overridden by
+ configuration (See `SHELL OPTIONS`_ and `SHELL INITRC`_ sections below)
+ * call ``shell.init`` plugin callbacks
+ * change working directory to the cwd of the job
+ * enter a barrier to ensure shell initialization is complete on all shells
+ * emit ``shell.init`` event to exec.eventlog
+ * call ``shell.post-init`` plugin callbacks
+ * create all local tasks. For each task, the following procedure is used
+
+ - call ``task.init`` plugin callback
+ - launch task, call ``task.exec`` plugin callback just before :linux:man2:`execve`
+ - call ``task.fork`` plugin callback
+
+ * once all tasks have started, call ``shell.start`` plugin callback
+ * enter shell "start" barrier
+ * emit ``shell.start`` event, after which all tasks are known running
+ * for each exiting task:
+
+ - call ``task.exit`` plugin callback
+ - collect exit status
+
+ * call ``shell.exit`` plugin callback when all tasks have exited.
+ * exit with max task exit code
+
+PLUGINS
+=======
+
+The job shell supports external and builtin plugins which implement most
+of the advanced job shell features. Job shell plugins are loaded into
+a plugin stack by name, where the last loaded name wins. Therefore, to
+override a builtin plugin, an alternate plugin which registers the same
+name may be loaded at runtime.
+
+.. note::
+ Job shell plugins should be written with the assumption their access
+ to Flux services may be restricted as a guest.
+
+C plugins are defined using the Flux standard plugin format. A shell C
+plugin should therefore export a single symbol ``flux_plugin_init()``, in
+which calls to ``flux_plugin_add_handler(3)`` should be used to register
+functions which will be invoked at defined points during shell execution.
+These callbacks are defined by "topic strings" to which plugins can
+"subscribe" by calling ``flux_plugin_add_handler(3)`` and/or
+``flux_plugin_register(3)`` with topic :linux:man7:`glob` strings.
+
+.. note::
+ ``flux_plugin_init(3)`` is not called for builtin shell plugins. If
+ a dynamically loaded plugin wishes to set shell options to influence
+ a shell builtin plugin (e.g. to disable its operation), it should
+ therefore do so in ``flux_plugin_init()`` in order to guarantee that
+ the shell option is set before the builtin attempts to read them.
+
+Simple plugins may also be developed directly in the shell ``initrc.lua``
+file itself (see `SHELL INITRC`_ section, ``plugin.register()`` below)
+
+By default, :program:`flux shell` supports the following plugin callback
+topics:
+
+**taskmap.SCHEME**
+ Called when a taskmap scheme *SCHEME* is requested via the taskmap
+ shell option or corresponding :option:`flux submit --taskmap` option.
+ Plugins that want to offer a different taskmap scheme than the defaults
+ of ``block``, ``cyclic``, ``hostfile``, and ``manual`` can register a
+ ``taskmap.*`` plugin callback and then users can request this mapping
+ with the appropriate :option:`flux submit --taskmap=name`` option.
+ The default block taskmap is passed to the plugin as "taskmap" in the
+ plugin input arguments, and the plugin should return the new taskmap as a
+ string in the output args. This callback is called before ``shell.init``.
+
+**shell.connect**
+ Called just after the shell connects to the local Flux broker. (Only
+ available to builtin shell plugins.)
+
+**shell.init**
+ Called after the shell has finished fetching and parsing the
+ **jobspec** and **R** from the KVS, but before any tasks
+ are started.
+
+**shell.post-init**
+ Called after the shell initialization barrier has completed, but
+ before starting any tasks.
+
+**task.init**
+ Called for each task after the task info has been constructed
+ but before the task is executed.
+
+**task.exec**
+ Called for each task after the task has been forked just before
+ :linux:man2:`execve` is called. This callback is made from within the
+ task process.
+
+**task.fork**
+ Called for each task after the task if forked from the parent
+ process (:program:`flux shell` process)
+
+**task.exit**
+ Called for each task after it exits and wait_status is available.
+
+**shell.start**
+ Called after all local tasks have been started. The shell "start"
+ barrier is called just after this callback returns.
+
+**shell.log**
+ Called by the shell logging facility when a shell component
+ posts a log message.
+
+**shell.log-setlevel**
+ Called by the shell logging facility when a request to set the
+ shell loglevel is made.
+
+
+Note however, that plugins may also call into the plugin stack to create
+new callbacks at runtime, so more topics than those listed above may be
+available in a given shell instance.
+
+.. _flux_shell_options:
+
+SHELL OPTIONS
+=============
+
+On startup, :program:`flux shell` will examine the jobspec for any shell
+specific options under the ``attributes.system.shell.options`` key. These
+options may be set by the :option:`flux submit -o, --setopt=OPT` option,
+or explicitly added to the jobspec by other means.
+
+Job shell options may be switches to enable or disable a shell feature or
+plugin, or they may take an argument. Because jobspec is a JSON document,
+job shell options in jobspec may take arguments that are themselves
+JSON objects. This allows maximum flexibility in runtime configuration
+of optional job shell behavior. In the list below, if an option doesn't
+include a ``=``, then it is a simple boolean option or switch and may be
+specified simply with :option:`flux submit -o OPTION`.
+
+Job shell plugins may also support configuration via shell options in
+the jobspec. For specific information about runtime-loaded plugins,
+see the documentation for the specific plugin in question.
+
+Shell options supported by :program:`flux shell` itself and its built-in
+plugins include:
+
+.. option:: verbose[=INT]
+
+ Set the shell verbosity to *INT*. A larger value indicates increased
+ verbosity, though setting this value larger than 2 currently has no
+ effect.
+
+.. option:: nosetpgrp
+
+ Disable the use of :linux:man2:`setpgrp` to launch each
+ job task in its own process group. This will cause signals to be
+ delivered only to direct children of the shell.
+
+.. option:: initrc=FILE
+
+ Load :program:`flux shell` initrc.lua file from *FILE* instead of the default
+ initrc path. For details of the job shell initrc.lua file format,
+ see the `SHELL INITRC`_ section below.
+
+.. option:: userrc=FILE
+
+ Load another initrc.lua file after the system one. For details of the
+ job shell initrc.lua file format, see the `SHELL INITRC`_ section below.
+
+.. option:: pty
+
+ Allocate a pty to all task ranks for non-interactive use. Output
+ from all ranks will be captured to the same location as ``stdout``.
+ This is the same as setting :option:`pty.ranks=all` and :option:`pty.capture`.
+ (see below).
+
+.. option:: pty.ranks=OPT
+
+ Set the task ranks for which to allocate a pty. *OPT* may be either
+ an RFC 22 IDset of target ranks, an integer rank, or the string "all"
+ to indicate all ranks.
+
+.. option:: pty.capture
+
+ Enable capture of pty output to the same location as stdout. This is
+ the default unless :option:`pty.interactive` is set.
+
+.. option:: pty.interactive
+
+ Enable a a pty on rank 0 that is set up for interactive attach by
+ a front-end program (i.e. :program:`flux job attach`). With no other
+ :option:`pty` options, only rank 0 will be assigned a pty and output will not
+ be captured. These defaults can be changed by setting other
+ :option:`pty` options after :option:`pty.interactive`, e.g.
+
+ .. code-block:: console
+
+ $ flux run -o pty.interactive -o pty.capture ...
+
+ would allocate an interactive pty on rank 0 and also capture the
+ pty session to the KVS (so it can be displayed after the job exits
+ with ``flux job attach``).
+
+.. option:: cpu-affinity=OPT
+
+ Adjust the operation of the builtin shell ``affinity`` plugin. If the
+ option is unspecified, ``on`` is assumed. *OPT* may be set to:
+
+ on
+ Bind each task to the full set of cores allocated to the job.
+
+ off
+ Disable the affinity plugin. This may be useful if using another plugin
+ such as `mpibind `_ to manage CPU
+ affinity.
+
+ per-task
+ Bind each task to an evenly populated subset of the cores allocated to
+ the job. Tasks share cores only if there are more tasks than cores.
+
+ map:LIST
+ Bind each task to *LIST*, a semicolon-delimited list of cores.
+ Each entry in the list can be in one of the :linux:man7:`hwloc`
+ *list*, *bitmask*, or *taskset* formats. See `hwlocality_bitmap(3)
+ `_,
+ especially the :func:`hwloc_bitmap_list_snprintf`,
+ :func:`hwloc_bitmap_snprintf` and :func:`hwloc_bitmap_taskset_snprintf`
+ functions.
+
+.. option:: gpu-affinity=OPT
+
+ Adjust operation of the builtin shell ``gpubind`` plugin. This plugin
+ sets :envvar:`CUDA_VISIBLE_DEVICES` to the GPU IDs allocated to the job.
+ If the option is unspecified, ``on`` is assumed. *OPT* may be set to:
+
+ on
+ Constrain each task to the full set of GPUs allocated to the job.
+
+ off
+ Disable the gpu-affinity plugin.
+
+ per-task
+ Constrain each task to an evenly populated subset of the GPUs allocated
+ to the job. Tasks share GPUs only if there are more tasks than GPUs.
+
+ map:LIST
+ Constrain each task to *LIST*, a semicolon-delimited list of GPUs.
+ See :option:`cpu-affinity` above for a description of *LIST* format.
+
+.. option:: stop-tasks-in-exec
+
+ Stops tasks in ``exec()`` using ``PTRACE_TRACEME``. Used for debugging
+ parallel jobs. Users should not need to set this option directly.
+
+.. option:: output.{stdout,stderr}.type=TYPE
+
+ Set job output to for **stderr** or **stdout** to *TYPE*. *TYPE* may
+ be one of ``term``, ``kvs`` or ``file`` (Default: ``kvs``). If only
+ ``output.stdout.type`` is set, then this option applies to both
+ ``stdout`` and ``stderr``. If set to ``file``, then ``output..path``
+ must also be set for the stream. Most users will not need to set
+ this option directly, as it will be set automatically by options
+ of higher level commands such as :man1:`flux-submit`.
+
+.. option:: output.limit=SIZE
+
+ Truncate KVS output after SIZE bytes have been written. SIZE may
+ be a floating point value with optional SI units k, K, M, G. The maximum
+ value is 1G. The default KVS output limit is 10M for jobs
+ in a multi-user instance or 1G for single-user instance jobs.
+ This value is ignored if output is directed to a file.
+
+.. option:: output.{stdout,stderr}.path=PATH
+
+ Set job stderr/out file output to PATH.
+
+.. option:: output.mode=truncate|append
+
+ Set the mode in which output files are opened to either truncate or
+ append. The default is to truncate.
+
+.. option:: input.stdin.type=TYPE
+
+ Set job input for **stdin** to *TYPE*. *TYPE* may be either ``service``
+ or ``file``. Users should not need to set this option directly as it
+ will be handled by options of higher level commands like :man1:`flux-submit`.
+
+.. option:: exit-timeout=VALUE
+
+ A fatal exception is raised on the job 30s after the first task exits.
+ The timeout period may be altered by providing a different value in
+ Flux Standard Duration form. A value of ``none`` disables generation of
+ the exception.
+
+.. option:: exit-on-error
+
+ If the first task to exit was signaled or exited with a nonzero status,
+ raise a fatal exception on the job immediately.
+
+.. option:: rlimit
+
+ A dictionary of soft process resource limits to apply to the job before
+ starting tasks. Resource limits are set to integer values by lowercase
+ name without the ``RLIMIT_`` prefix, e.g. ``core`` or ``nofile``. Users
+ should not need to set this shell option as it is handled by commands
+ like :man1:`flux-submit`.
+
+.. option:: taskmap
+
+ Request an alternate job task mapping. This option is an object
+ consisting of required key ``scheme`` and optional key ``value``. The
+ shell will attempt to call a ``taskmap.scheme`` plugin callback in the
+ shell to invoke the alternate requested mapping. If ``value`` is set,
+ this will also be passed to the invoked plugin. Normally, this option will
+ be set by the :man1:`flux-submit` and related commands :option:`--taskmap`
+ option.
+
+.. option:: pmi=LIST
+
+ Specify a comma-separated list of PMI implementations to enable. If the
+ option is unspecified, ``simple`` is assumed. To disable, set *LIST* to
+ ``off``. Available implementations include
+
+ simple
+ The simple PMI-1 wire protocol. This implementation works by passing an
+ open file descriptor to clients via the :envvar:`PMI_FD` environment
+ variable. It must be enabled when Flux's ``libpmi.so`` or ``libpmi2.so``
+ libraries are used, and is preferred by :man1:`flux-broker`
+ when Flux launches Flux, e.g. by means of :man1:`flux-batch` or
+ :man1:`flux-alloc`.
+
+ pmi1, pmi2
+ Aliases for ``simple``.
+
+ cray-pals
+ Provided via external plugin from the
+ `flux-coral2 `_ project.
+
+ pmix
+ Provided via external plugin from the
+ `flux-pmix `_ project.
+
+.. option:: pmi-simple.nomap
+
+ Skip pre-populating the ``flux.taskmap`` and ``PMI_process_mapping`` keys
+ in the ``simple`` implementation.
+
+.. option:: pmi-simple.kvs=native
+
+ Use the native Flux KVS instead of the PMI plugin's built-in key exchange
+ algorithm in the ``simple`` implementation.
+
+.. option:: pmi-simple.exchange.k=N
+
+ Configure the PMI plugin's built-in key exchange algorithm to use a
+ virtual tree fanout of ``N`` for key gather/broadcast in the ``simple``
+ implementation. The default is 2.
+
+.. option:: stage-in
+
+ Copy files to the directory referenced by :envvar:`FLUX_JOB_TMPDIR` that
+ were previously archived with :man1:`flux-archive`.
+
+.. option:: stage-in.names=LIST
+
+ Select archives to extract by specifying a comma-separated list of names
+ If no names are specified, ``main`` is assumed.
+
+.. option:: stage-in.pattern=PATTERN
+
+ Further filter the selected files to copy using a :man7:`glob` pattern.
+
+.. option:: stage-in.destination=[SCOPE:]PATH
+
+ Copy files to the specified destination instead of the directory referenced
+ by :envvar:`FLUX_JOB_TMPDIR`. The argument is a directory with optional
+ *scope* prefix. A scope of ``local`` denotes a local file system (the
+ default), and a scope of ``global`` denotes a global file system. The copy
+ takes place on all the job's nodes if the scope is local, versus only the
+ first node of the job if the scope is global.
+
+.. option:: signal=OPTION
+
+ Deliver signal ``SIGUSR1`` to the job 60s before job expiration.
+ To customize the signal number or amount of time before expiration to
+ deliver the signal, the ``signal`` option may be an object with one
+ or both of the keys ``signum`` or ``timeleft``. (See below)
+
+.. option:: signal.signum=NUMBER
+
+ Send signal *NUMBER* to the job :option:`signal.timeleft` seconds before
+ the time limit.
+
+.. option:: signal.timeleft=TIME
+
+ Send signal :option:`signal.signum` *TIME* seconds before job expiration.
+
+.. option:: hwloc.xmlfile
+
+ Write the job shell's copy of hwloc XML to a file and set ``HWLOC_XMLFILE``.
+ Note that this option will also unset ``HWLOC_COMPONENTS`` since presence
+ of this environment variable may cause hwloc to ignore ``HWLOC_XMLFILE``.
+
+.. option:: hwloc.restrict
+
+ With :option:`hwloc.xmlfile`, restrict the exported topology XML to only
+ the resources assigned to the current job. By default the XML is not
+ restricted.
+
+.. warning::
+ The directory referenced by :envvar:`FLUX_JOB_TMPDIR` is cleaned up when the
+ job ends, is guaranteed to be unique, and is generally on fast local storage
+ such as a *tmpfs*. If a destination is explicitly specified, use the
+ ``global:`` prefix where appropriate to avoid overwhelming a shared file
+ system, and be sure to clean up.
+
+.. _flux_shell_initrc:
+
+SHELL INITRC
+============
+
+At initialization, :program:`flux shell` reads a Lua initrc file which can be
+used to customize the shell operation. The initrc is loaded by default from
+``$sysconfdir/flux/shell/initrc.lua`` (or ``/etc/flux/shell/initrc.lua``
+for a "standard" install), but a different path may be specified when
+launching a job via the ``initrc`` shell option. Alternatively, the ``userrc``
+shell option can specify an initrc file to load after the system one.
+
+A job shell initrc file may be used to adjust the shell plugin searchpath,
+load specific plugins, read and set shell options, and even extend the
+shell itself using Lua.
+
+Since the job shell ``initrc`` is a Lua file, any Lua syntax is
+supported. Job shell specific functions and tables are described below:
+
+**plugin.searchpath**
+ The current plugin searchpath. This value can be queried, set,
+ or appended. E.g. to add a new path to the plugin search path:
+ ``plugin.searchpath = plugin.searchpath .. ':' .. path``
+
+**plugin.load({file=glob, [conf=table]})**
+ Explicitly load one more shell plugins. This function takes a table
+ argument with ``file`` and ``conf`` arguments. The ``file`` argument
+ is a glob of one or more plugins to load. If an absolute path is not
+ specified, then the glob will be relative to ``plugin.searchpath``.
+ E.g. ``plugin.load { file = "*.so" }`` will load all ``.so`` plugins in
+ the current search path. The ``conf`` option allows static configuration
+ values to be passed to plugin initialization functions when supported.
+
+ For example a plugin ``test.so`` may be explicitly loaded with
+ configuration via:
+
+ .. code-block:: lua
+
+ plugin.load { file = "test.so", conf = { value = "foo" } }
+
+**plugin.register({name=plugin_name, handlers=handlers_table)**
+ Register a Lua plugin. Requires a table argument with the plugin ``name``
+ and a set of ``handlers``. ``handlers_table`` is an array of tables, each
+ of which must define ``topic``, a topic glob of shell plugin callbacks to
+ which to subscribe, and ``fn`` a handler function to call for each match
+
+ For example, the following plugin would log the topic string for
+ every possible plugin callback (except for callbacks which are made
+ before the shell logging facility is initialized)
+
+ .. code-block:: lua
+
+ plugin.register {
+ name = "test",
+ handlers = {
+ { topic = "*",
+ fn = function (topic) shell.log ("topic="..topic) end
+ },
+ }
+ }
+
+**source(glob)**
+ Source another Lua file or files. Supports specification of a glob,
+ e.g. ``source ("*.lua")``. This function fails if a non-glob argument
+ specifies a file that does not exist, or there is an error loading or
+ compiling the Lua chunk.
+
+**source_if_exists(glob)**
+ Same as ``source()``, but do not throw an error if the target file does
+ not exist.
+
+**shell.rcpath**
+ The directory in which the current initrc file resides.
+
+**shell.getenv([name])**
+ Return the job environment (not the job shell environment). This is
+ the environment which will be inherited by the job tasks. If called
+ with no arguments, then the entire environment is copied to a table
+ and returned. Otherwise, acts as :man3:`flux_shell_getenv` and returns
+ the value for the environment variable name, or ``nil`` if not set.
+
+**shell.setenv(var, val, [overwrite])**
+ Set environment variable ``var`` to value ``val`` in the job environment.
+ If ``overwrite`` is set and is ``0`` or ``false`` then do not overwrite
+ existing environment variable value.
+
+**shell.unsetenv(var)**
+ Unset environment variable ``var`` in job environment.
+
+**shell.options**
+ A virtual index into currently set shell options, including those
+ set in jobspec. This table can be used to check jobspec options,
+ and even to force certain options to a value by default e.g.
+ ``shell.options['cpu-affinity'] = "per-task"``, would force
+ ``cpu-affinity`` shell option to ``per-task``.
+
+**shell.options.verbose**
+ Current :program:`flux shell` verbosity. This value may be changed at
+ runtime, e.g. ``shell.options.verbose = 2`` to set maximum verbosity.
+
+**shell.info**
+ Returns a Lua table of shell information obtained via
+ :man3:`flux_shell_get_info`. This table includes
+
+ **jobid**
+ The current jobid.
+ **rank**
+ The rank of the current shell within the job.
+ **size**
+ The number of :program:`flux shell` processes participating in this job.
+ **ntasks**
+ The total number of tasks in this job.
+ **service**
+ The service string advertised by the shell.
+ **options.verbose**
+ True if the shell is running in verbose mode.
+ **jobspec**
+ The jobspec of the current job
+ **R**
+ The resource set **R** of the current job
+
+**shell.rankinfo**
+ Returns a Lua table of rank-specific shell information for the
+ current shell rank. See `shell.get_rankinfo()` for a description
+ of the members of this table.
+
+**shell.get_rankinfo(shell_rank)**
+ Query rank-specific shell info as in the function call
+ :man3:`flux_shell_get_rank_info`. If ``shell_rank`` is not provided
+ then the current rank is used. Returns a table of rank-specific
+ information including:
+
+ **broker_rank**
+ The broker rank on which ``shell_rank`` is running.
+ **ntasks**
+ The number of local tasks assigned to ``shell_rank``.
+ **resources**
+ A table of resources by name (e.g. "core", "gpu") assigned to
+ ``shell_rank``, e.g. ``{ core = "0-1", gpu = "0" }``.
+
+**shell.log(msg)**, **shell.debug(msg)**, **shell.log_error(msg)**
+ Log messages to the shell log facility at INFO, DEBUG, and ERROR
+ levels respectively.
+
+**shell.die(msg)**
+ Log a FATAL message to the shell log facility. This generates a
+ job exception and will terminate the job.
+
+The following task-specific initrc data and functions are available
+only in one of the ``task.*`` plugin callbacks. An error will be
+generated if they are accessed from any other context.
+
+**task.info**
+ Returns a Lua table of task specific information for the "current"
+ task (see :man3:`flux_shell_task_get_info`). Included members of
+ the ``task.info`` table include:
+
+ **localid**
+ The local task rank (i.e. within this shell)
+ **rank**
+ The global task rank (i.e. within this job)
+ **state**
+ The current task state name
+ **pid**
+ The process id of the current task (if task has been started)
+ **wait_status**
+ (Only in ``task.exit``) The status returned by
+ :linux:man2:`waitpid` for this task.
+ **exitcode**
+ (Only in ``task.exit``) The exit code if ``WIFEXTED()`` is true.
+ **signaled**
+ (Only in ``task.exit``) If task was signaled, this member will be
+ non-zero integer signal number that caused the task to exit.
+
+**task.getenv(var)**
+ Get the value of environment variable ``var`` if set in the current
+ task's environment. This function reads the environment from the
+ underlying ``flux_cmd_t`` for a shell task, and thus only makes sense
+ before a task is executed, e.g. in ``task.init`` and ``task.exec``
+ callbacks.
+
+**task.unsetenv(var)**
+ Unset environment variable ``var`` for the current task. As with
+ ``task.getenv()`` this function is only valid before a task has
+ been started.
+
+**task.setenv(var, value, [overwrite])**
+ Set environment variable ``var`` to ``val`` for the current task.
+ If ``overwrite`` is set to ``0`` or ``false``, then do not overwrite
+ any current value. As with ``task.getenv()`` and ``task.unsetenv()``,
+ this function only has an effect before the task is started.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-submit`
diff --git a/doc/man1/flux-shutdown.rst b/doc/man1/flux-shutdown.rst
new file mode 100644
index 000000000000..a427ef871ecf
--- /dev/null
+++ b/doc/man1/flux-shutdown.rst
@@ -0,0 +1,111 @@
+================
+flux-shutdown(1)
+================
+
+
+SYNOPSIS
+========
+
+**flux** **shutdown** [*OPTIONS*] [*TARGET*]
+
+
+DESCRIPTION
+===========
+
+.. program:: flux shutdown
+
+The :program:`flux shutdown` command causes the default Flux instance, or the
+instance specified by *TARGET*, to exit RUN state and begin the process
+of shutting down. *TARGET* may be either a native Flux URI or a high level
+URI, as described in :man1:`flux-uri`.
+
+Only the rank 0 broker in RUN state may be targeted for shutdown.
+The current broker state may be viewed with :man1:`flux-uptime`.
+
+If the instance is running an initial program, that program is terminated
+with SIGHUP. Note that the broker exit value normally reflects the
+exit code of the initial program, so if it is terminated by this signal,
+the broker exits with 128 + 1 = 129.
+
+If the broker was launched by systemd, an exit code is used that informs
+systemd not to restart the broker.
+
+Broker log messages that are posted during shutdown are displayed by
+the shutdown command on stderr, until the broker completes executing its
+``rc3`` script. By default, log messages with severity level <= LOG_INFO
+are printed.
+
+A Flux system instance requires offline KVS garbage collection to remove
+deleted KVS content and purged job directories, which accrue over time and
+increase storage overhead and restart time. It is recommended that the
+:option:`--gc` option be used on a routine basis to optimize Flux.
+
+
+OPTIONS
+=======
+
+:program:`flux shutdown` accepts the following options:
+
+.. option:: -h, --help
+
+ Display options and exit
+
+.. option:: --background
+
+ Start the shutdown and exit immediately, without monitoring the process
+ and displaying log messages.
+
+.. option:: --quiet
+
+ Show only error log messages (severity level <= LOG_WARNING level).
+
+.. option:: --verbose=[LEVEL]
+
+ Increase output verbosity. Level 1 shows all log messages. Higher
+ verbosity levels are reserved for future use.
+
+.. option:: --dump=PATH
+
+ Dump a checkpoint of KVS content to *PATH* using :man1:`flux-dump` after the
+ KVS has been unloaded. The dump may be restored into a new Flux instance
+ using :man1:`flux-restore`. Dump creation adds time to the shutdown
+ sequence, proportional to the amount of data in the KVS.
+ :option:`--dump=auto` is a special case equivalent to :option:`--gc`.
+
+.. option:: --gc
+
+ Prepare for offline KVS garbage collection by dumping a checkpoint of KVS
+ content to ``dump/.tgz`` in *statedir*, if defined, otherwise in
+ the broker's current working directory. Create a symbolic link named
+ ``dump/RESTORE`` pointing to the dump file. When this link is discovered
+ on instance startup, the content database is truncated and recreated from
+ the dump, and the link is removed. :linux:man8:`systemd-tmpfiles`
+ automatically cleans up dump files in ``/var/lib/flux/dump`` after 30 days.
+
+.. option:: --skip-gc
+
+ When garbage collection has been enabled automatically, as indicated
+ by the ``content.dump`` broker attribute, this option disables it
+ during shutdown. Otherwise it is a preemptive "no" answer to the garbage
+ collection prompt.
+
+.. option:: -y, --yes
+
+ Answer yes to any yes/no questions.
+
+.. option:: -n, --no
+
+ Answer no to any yes/no questions.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-start`, :man1:`flux-uptime`, :man1:`flux-uri`, :man1:`flux-dump`,
+:man5:`flux-config-kvs`,:linux:man8:`systemd-tmpfiles`
diff --git a/doc/man1/flux-start.adoc b/doc/man1/flux-start.adoc
deleted file mode 100644
index e77853e25c4e..000000000000
--- a/doc/man1/flux-start.adoc
+++ /dev/null
@@ -1,104 +0,0 @@
-// flux-help-include: true
-FLUX-START(1)
-=============
-:doctype: manpage
-
-
-NAME
-----
-flux-start - bootstrap a local Flux instance
-
-
-SYNOPSIS
---------
-*flux* *start* ['OPTIONS'] [initial-program [args...]]
-
-
-DESCRIPTION
------------
-flux-start(1) launches a new Flux instance. By default, flux-start
-execs a single flux-broker(1) directly. By default it will attempt to use
-PMI to fetch job information and bootstrap a flux instance.
-
-If a size is specified via '--size', an instance of that size is to be
-started on the local host with flux-start as the parent. (Mostly used for testing
-purposes.)
-
-A failure of the initial program (such as non-zero exit code)
-causes flux-start to exit with a non-zero exit code.
-
-Note: in order to launch a Flux instance, you must have generated
-long-term CURVE keys using flux-keygen(1).
-
-OPTIONS
--------
-*-s, --size*='N'::
-Launch an instance of size 'N' on the local host. Only works with
-'--bootstrap=selfpmi'. Automatically sets '--bootstrap=selfpmi' and prints
-a warning to stderr if no '--bootstrap' option is specified.
-
-*-b, --bootstrap*='METHOD'::
-Select the flux bootstrap method. Possible values of 'METHOD' are:
- * pmi - Use PMI (Process Management Interface)
- * selfpmi - The flux-start process will activate its own internal PMI server,
- and then it will launch flux-brokers that will bootstrap using said PMI server.
-
-*-o, --broker-opts*='option_string'::
-Add options to the message broker daemon, separated by commas.
-
-*-v, --verbose*::
-Display commands before executing them.
-
-*-X, --noexec*::
-Don't execute anything. This option is most useful with -v.
-
-*--caliper-profile*='PROFILE'::
-Run brokers with Caliper profiling enabled, using a Caliper
-configuration profile named 'PROFILE'. Requires a version of Flux
-built with --enable-caliper. Unless CALI_LOG_VERBOSITY is already
-set in the environment, it will default to 0 for all brokers.
-
-*--scratchdir*='DIR'::
-For selfpmi bootstrap mode, set the directory that will be
-used as the rundir directory for the instance. If the directory
-does not exist then it will be created during instance startup.
-If a DIR is not set with this option, a unique temporary directory
-will be created. Unless DIR was pre-existing, it will be removed
-when the instance is destroyed.
-
-*--wrap*='ARGS,...'::
-Wrap broker execution in a comma-separated list of arguments. This is
-useful for running flux-broker directly under debuggers or valgrind.
-
-
-EXAMPLES
---------
-
-Launch an 8-way local Flux instance with an interactive shell as the
-initial program and all logs output to stderr:
-
- flux start -s8 -o,--setattr=log-stderr-level=7
-
-Launch an 8-way Flux instance within a slurm job, with an interactive
-shell as the initial program:
-
- srun --pty -N8 flux start
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-flux-broker(1) flux-keygen(1)
diff --git a/doc/man1/flux-start.rst b/doc/man1/flux-start.rst
new file mode 100644
index 000000000000..a7c4acda847b
--- /dev/null
+++ b/doc/man1/flux-start.rst
@@ -0,0 +1,312 @@
+.. flux-help-include: true
+
+=============
+flux-start(1)
+=============
+
+
+SYNOPSIS
+========
+
+[**launcher**] **flux** **start** [*OPTIONS*] [initial-program [args...]]
+
+**flux** **start** *--test-size=N* [*OPTIONS*] [initial-program [args...]]
+
+DESCRIPTION
+===========
+
+.. program:: flux start
+
+:program:`flux start` assists with launching a new Flux instance, which
+consists of one or more :man1:`flux-broker` processes functioning as a
+distributed system. It is primarily useful in environments that don't run
+Flux natively, or when a standalone Flux instance is required for test,
+development, or post-mortem debugging of another Flux instance.
+
+When already running under Flux, single-user Flux instances can be more
+conveniently started with :man1:`flux-batch` and :man1:`flux-alloc`.
+The `Flux Administration Guide
+`_
+covers setting up a multi-user Flux "system instance", where Flux natively
+manages a cluster's resources and those commands work ab initio for its users.
+
+:program:`flux start` operates in two modes. In `NORMAL MODE`_, it does not
+launch broker processes; it *becomes* a single broker which joins an externally
+bootstrapped parallel program. In `TEST MODE`_, it starts one or more brokers
+locally, provides their bootstrap environment, and then cleans up when the
+instance terminates.
+
+NORMAL MODE
+===========
+
+Normal mode is used when an external launcher like Slurm or Hydra starts
+the broker processes and provides the bootstrap environment. It is selected
+when the :option:`--test-size` option is *not* specified.
+
+In normal mode, :program:`flux start` replaces itself with a broker process
+by calling :linux:man2:`execvp`. The brokers bootstrap as a parallel program
+and establish overlay network connections. The usual bootstrap method is
+some variant of the Process Management Interface (PMI) provided by the
+launcher.
+
+For example, Hydra provides a simple PMI server. The following command
+starts brokers on the hosts listed in a file called ``hosts``. The
+instance's initial program prints a URI that can be used with
+:man1:`flux-proxy` and then sleeps forever::
+
+ mpiexec.hydra -f hosts -launcher ssh \
+ flux start "flux uri --remote \$FLUX_URI; sleep inf"
+
+Slurm has a PMI-2 server plugin with backwards compatibility to the simple
+PMI-1 wire protocol that Flux prefers. The following command starts a two
+node Flux instance in a Slurm allocation, with an interactive shell as the
+initial program (the default if none is specified)::
+
+ srun -N2 --pty --mpi=pmi2 flux start
+
+When Flux is started by a launcher that is not Flux, resources are probed
+using `HWLOC `_. If all goes well,
+when Slurm launches Flux :option:`flux resource info` in Flux should show all
+the nodes, cores, and GPUs that Slurm allocated to the job.
+
+TEST MODE
+=========
+
+Test mode, selected by specifying the :option:`--test-size` option, launches
+a single node Flux instance that is independent of any configured resource
+management on the node. In test mode, :program:`flux start` provides the
+bootstrap environment and launches the broker process(es). It remains running
+as long as the Flux instance is running. It covers the following use cases:
+
+- Start an interactive Flux instance on one node such as a developer system
+ ::
+
+ flux start --test-size=1
+
+ Jobs can be submitted from the interactive shell started as the initial
+ program, similar to the experience of running on a one node cluster.
+
+- Mock a multi-node (multi-broker) Flux instance on one node
+ ::
+
+ flux start --test-size=64
+
+ When the test size is greater than one, the actual resource inventory is
+ multiplied by the test size, since each broker thinks it
+ is running on a different node and re-discovers the same resources.
+
+- Start a Flux instance to run a continuous integration test. A test
+ that runs jobs in Flux can be structured as::
+
+ flux start --test-size=1 test.sh
+
+ where ``test.sh`` (the initial program) runs work under Flux. The exit
+ status of :program:`flux start` reflects the exit status of ``test.sh``.
+ This is how many of Flux's own tests work.
+
+- Start a Flux instance to access job data from an inactive batch job that
+ was configured to leave a dump file::
+
+ flux start --test-size=1 --recovery=dump.tar
+
+- Start a Flux instance to repair the on-disk state of a crashed system
+ instance (experts only)::
+
+ sudo -u flux flux start --test-size=1 --recovery
+
+- Run the broker under :linux:man1:`gdb` from the source tree::
+
+ ${top_builddir}/src/cmd/flux start --test-size=1 \
+ --wrap=libtool,e,gdb
+
+
+OPTIONS
+=======
+.. option:: -S, --setattr=ATTR=VAL
+
+ Set broker attribute *ATTR* to *VAL*. This is equivalent to
+ :option:`-o,-SATTR=VAL`.
+
+.. option:: -c, --config-path=PATH
+
+ Set the *PATH* for broker configuration. See :man1:`flux-broker` for
+ option details. This is equivalent to :option:`-o,-cPATH`.
+
+.. option:: -o, --broker-opts=OPTIONS
+
+ Add options to the message broker daemon, separated by commas.
+
+.. option:: -v, --verbose=[LEVEL]
+
+ This option may be specified multiple times, or with a value, to
+ set a verbosity level (1: display commands before executing them,
+ 2: trace PMI server requests in `TEST MODE`_ only).
+
+.. option:: -X, --noexec
+
+ Don't execute anything. This option is most useful with -v.
+
+.. option:: --rundir=DIR
+
+ (only with :option:`--test-size`) Set the directory that will be
+ used as the rundir directory for the instance. If the directory
+ does not exist then it will be created during instance startup.
+ If a DIR is not set with this option, a unique temporary directory
+ will be created. Unless DIR was pre-existing, it will be removed
+ when the instance is destroyed.
+
+.. option:: --wrap=ARGS
+
+ Wrap broker execution in a comma-separated list of arguments. This is
+ useful for running flux-broker directly under debuggers or valgrind.
+
+.. option:: -s, --test-size=N
+
+ Launch an instance of size *N* on the local host.
+
+.. option:: --test-hosts=HOSTLIST
+
+ Set :envvar:`FLUX_FAKE_HOSTNAME` in the environment of each broker so that
+ the broker can bootstrap from a config file instead of PMI. HOSTLIST is
+ assumed to be in rank order. The broker will use the fake hostname to
+ find its entry in the configured bootstrap host array.
+
+.. option:: --test-exit-timeout=FSD
+
+ After a broker exits, kill the other brokers after a timeout (default 20s).
+
+.. option:: --test-exit-mode=MODE
+
+ Set the mode for the exit timeout. If set to ``leader``, the exit timeout
+ is only triggered upon exit of the leader broker, and the
+ :program:`flux start` exit code is that of the leader broker. If set to
+ ``any``, the exit timeout is triggered upon exit of any broker, and the
+ :program:`flux start` exit code is the highest exit code of all brokers.
+ Default: ``any``.
+
+.. option:: --test-start-mode=MODE
+
+ Set the start mode. If set to ``all``, all brokers are started immediately.
+ If set to ``leader``, only the leader is started. Hint: in ``leader`` mode,
+ use :option:`--setattr=broker.quorum=1` to let the initial program start
+ before the other brokers are online. Default: ``all``.
+
+.. option:: --test-rundir=PATH
+
+ Set the directory to be used as the broker rundir instead of creating a
+ temporary one. The directory must exist, and is not cleaned up unless
+ :option:`--test-rundir-cleanup` is also specified.
+
+.. option:: --test-rundir-cleanup
+
+ Recursively remove the directory specified with :option:`--test-rundir` upon
+ completion of :program:`flux start`.
+
+.. option:: --test-pmi-clique=MODE
+
+ Set the pmi clique mode, which determines how ``PMI_process_mapping`` is set
+ in the PMI server used to bootstrap the brokers. If ``none``, the mapping
+ is not created. If ``single``, all brokers are placed in one clique. If
+ ``per-broker``, each broker is placed in its own clique.
+ Default: ``single``.
+
+.. option:: -r, --recovery=[TARGET]
+
+ Start the rank 0 broker of an instance in recovery mode. If *TARGET*
+ is a directory, treat it as a *statedir* from a previous instance.
+ If *TARGET* is a file, treat it as an archive file from :man1:`flux-dump`.
+ If *TARGET* is unspecified, assume the system instance is to be recovered.
+ In recovery mode, any rc1 errors are ignored, broker peers are not allowed
+ to connect, and resources are offline.
+
+.. option:: --sysconfig
+
+ Run the broker with :option:`--config-path` set to the default system
+ instance configuration directory. This option is unnecessary if
+ :option:`--recovery` is specified without its optional argument. It may
+ be required if recovering a dump from a system instance.
+
+
+TROUBLESHOOTING
+===============
+
+`NORMAL MODE`_ requires Flux, the launcher, and the network to cooperate.
+If :program:`flux start` appears to hang, the following tips may be helpful:
+
+#. Reduce the size of the Flux instance to at most two nodes. This reduces the
+ volume of log data to look at and may be easier to allocate on a busy
+ system. Rule out the simple problems that can be reproduced with a small
+ allocation first.
+
+#. Use an initial program that prints something and exits rather than the
+ default interactive shell, in case there are problems with the launcher's
+ pty setup. Something like::
+
+ [launcher] flux start [options] echo hello world
+
+#. Ensure that standard output and error are being captured and add launcher
+ options to add rank prefixes to the output.
+
+ .. list-table::
+
+ * - Slurm
+ - :option:`--label`
+
+ * - Hydra
+ - :option:`-prepend-rank`
+
+ * - :man1:`flux-run`
+ - :option:`--label-io`
+
+#. Tell the broker to print its rank, size, and network endpoint by adding
+ the :option:`flux start -o,-v` option. If this doesn't happen, most likely
+ the PMI bootstrap is getting stuck.
+
+#. Trace Flux's PMI client on stderr by setting the FLUX_PMI_DEBUG environment
+ variable::
+
+ FLUX_PMI_DEBUG=1 [launcher] flux start ...
+
+#. Consider altering :envvar:`FLUX_PMI_CLIENT_METHODS` to better match the
+ launcher's PMI offerings. See :man7:`flux-environment`.
+
+#. A launcher's PMI capabilities can also be explored in a simplified way
+ using the :man1:`flux-pmi` client.
+
+#. If PMI is successful but the initial program fails to run, the brokers
+ may not be able to reach each other over the network. After one minute,
+ the rank 0 broker should log a "quorum delayed" message if this is true.
+
+#. Examine the network endpoints in the output above. Flux preferentially
+ binds to the IPv4 network address associated with the default route and
+ a random port. The address choice can be modified by setting the
+ :envvar:`FLUX_IPADDR_HOSTNAME` and/or :envvar:`FLUX_IPADDR_V6`.
+ See :man7:`flux-environment`.
+
+#. More logging can be enabled by adding the
+ :option:`flux start -Slog-stderr-level=7` option, which instructs the
+ broker to forward its internal log buffer to stderr. See
+ :man7:`flux-broker-attributes`.
+
+Another common failure mode is getting a single node instance when multiple
+nodes were expected. This can occur if no viable PMI server was found and the
+brokers fell back to singleton operation. It may be helpful to enable PMI
+tracing, check into launcher PMI options, and possibly adjust the order of
+options that Flux tries using :envvar:`FLUX_PMI_CLIENT_METHODS` as described
+above.
+
+Finally, if Flux starts but GPUs are missing from :option:`flux resource info`
+output, verify that the version of HWLOC that Flux is using was built with
+the appropriate GPU plugins.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-broker`
diff --git a/doc/man1/flux-startlog.rst b/doc/man1/flux-startlog.rst
new file mode 100644
index 000000000000..7ce5271eca42
--- /dev/null
+++ b/doc/man1/flux-startlog.rst
@@ -0,0 +1,71 @@
+================
+flux-startlog(1)
+================
+
+
+SYNOPSIS
+========
+
+**flux** **startlog**
+
+
+DESCRIPTION
+===========
+
+.. program:: flux startlog
+
+List the Flux instance's start and stop times, by interpreting the contents
+of the KVS ``admin.eventlog``.
+
+A ``start`` event is posted to the eventlog at startup, and a ``finish`` event
+is posted to the eventlog at finalization. The timestamps on the two events
+are used to calculate the instance run time, which is shown in the listing
+in Flux Standard Duration format.
+
+If the current ``start`` event is not immediately preceded by a ``finish``
+event (unless it is the first entry in the eventlog), then the Flux instance
+may have crashed and data may have been lost. If this is detected on instance
+startup, it is logged by the broker's ``rc1`` script on the next reboot.
+
+This command is not available to guest users.
+
+
+OPTIONS
+=======
+
+.. option:: -h, --help
+
+ Summarize available options.
+
+.. option:: --check
+
+ If the instance has most recently restarted from a crash, exit with a
+ return code of 1, otherwise 0.
+
+.. option:: --quiet
+
+ Suppress non-error output.
+
+.. option:: -v, --show-version
+
+ Show the flux-core software version associated with each start event.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_18`
+
+:doc:`rfc:spec_23`
+
+
+SEE ALSO
+========
+
+:man1:`flux-uptime`, :man1:`flux-kvs`
diff --git a/doc/man1/flux-submit.rst b/doc/man1/flux-submit.rst
new file mode 100644
index 000000000000..4bade399689f
--- /dev/null
+++ b/doc/man1/flux-submit.rst
@@ -0,0 +1,167 @@
+.. flux-help-include: true
+.. flux-help-section: submission
+
+==============
+flux-submit(1)
+==============
+
+
+SYNOPSIS
+========
+
+**flux** **submit** [OPTIONS] [*--ntasks=N*] COMMAND...
+
+
+DESCRIPTION
+===========
+
+.. program:: flux submit
+
+:program:`flux submit` enqueues a job to run under Flux and prints its
+numerical jobid on standard output. The job consists of *N* copies of COMMAND
+launched together as a parallel job.
+
+If :option:`--ntasks` is unspecified, a value of *N=1* is assumed.
+
+The available OPTIONS are detailed below.
+
+JOB PARAMETERS
+==============
+
+These commands accept only the simplest parameters for expressing
+the size of the parallel program and the geometry of its task slots:
+
+Common resource options
+-----------------------
+
+These commands take the following common resource allocation options:
+
+.. include:: common/job-param-common.rst
+
+Per-task options
+----------------
+
+:man1:`flux-run`, :man1:`flux-submit` and :man1:`flux-bulksubmit` take two
+sets of mutually exclusive options to specify the size of the job request.
+The most common form uses the total number of tasks to run along with
+the amount of resources required per task to specify the resources for
+the entire job:
+
+.. include:: common/job-param-pertask.rst
+
+Per-resource options
+--------------------
+
+The second set of options allows an amount of resources to be specified
+with the number of tasks per core or node set on the command line. It is
+an error to specify any of these options when using any per-task option
+listed above:
+
+.. include:: common/job-param-perres.rst
+
+Additional job options
+----------------------
+
+These commands also take following job parameters:
+
+.. include:: common/job-param-additional.rst
+
+STANDARD I/O
+============
+
+By default, task stdout and stderr streams are redirected to the
+KVS, where they may be accessed with the ``flux job attach`` command.
+
+In addition, :man1:`flux-run` processes standard I/O in real time,
+emitting the job's I/O to its stdout and stderr.
+
+.. include:: common/job-standard-io.rst
+
+CONSTRAINTS
+===========
+
+.. include:: common/job-constraints.rst
+
+DEPENDENCIES
+============
+
+.. include:: common/job-dependencies.rst
+
+ENVIRONMENT
+===========
+
+By default, these commands duplicate the current environment when submitting
+jobs. However, a set of environment manipulation options are provided to
+give fine control over the requested environment submitted with the job.
+
+.. include:: common/job-environment.rst
+
+ENV RULES
+---------
+
+.. include:: common/job-env-rules.rst
+
+PROCESS RESOURCE LIMITS
+=======================
+
+By default these commands propagate some common resource limits (as described
+in :linux:man2:`getrlimit`) to the job by setting the ``rlimit`` job shell
+option in jobspec. The set of resource limits propagated can be controlled
+via the :option:`--rlimit=RULE` option:
+
+.. include:: common/job-process-resource-limits.rst
+
+JOB ENVIRONMENT VARIABLES
+=========================
+
+The job environment is described in more detail in the :man7:`flux-environment`
+:ref:`job_environment` section. A summary of the most commonly used variables
+is provided below:
+
+.. include:: common/job-environment-variables.rst
+
+EXIT STATUS
+===========
+
+The job exit status, normally the largest task exit status, is stored
+in the KVS. If one or more tasks are terminated with a signal,
+the job exit status is 128+signo.
+
+The ``flux-job attach`` command exits with the job exit status.
+
+In addition, :man1:`flux-run` runs until the job completes and exits
+with the job exit status.
+
+OTHER OPTIONS
+=============
+
+.. include:: common/job-other-options.rst
+
+.. include:: common/job-other-run.rst
+
+SHELL OPTIONS
+=============
+
+Some options that affect the parallel runtime environment are provided by the
+Flux shell. These options are described in detail in the
+:ref:`SHELL OPTIONS ` section of :man1:`flux-shell`.
+A list of the most commonly needed options follows.
+
+Usage: :option:`flux submit -o NAME[=ARG]`.
+
+.. make :option: references in the included table x-ref to flux-shell(1)
+.. program:: flux shell
+.. include:: common/job-shell-options.rst
+.. program:: flux submit
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-run`, :man1:`flux-alloc`, :man1:`flux-batch`,
+:man1:`flux-bulksubmit`, :man7:`flux-environment`
diff --git a/doc/man1/flux-top.rst b/doc/man1/flux-top.rst
new file mode 100644
index 000000000000..d1c1b086edad
--- /dev/null
+++ b/doc/man1/flux-top.rst
@@ -0,0 +1,166 @@
+.. flux-help-description: display running Flux jobs
+.. flux-help-section: jobs
+
+===========
+flux-top(1)
+===========
+
+
+SYNOPSIS
+========
+
+**flux** **top** [*OPTIONS*] [*TARGET*]
+
+
+DESCRIPTION
+===========
+
+.. program:: flux top
+
+The :program:`flux top` command provides a dynamic view of Flux instance status
+and running jobs. *TARGET*, if specified, selects a Flux instance other
+than the default, and may be either a native Flux URI or a high level URI,
+as described in :man1:`flux-uri`.
+
+The :program:`flux top` display window is divided into two parts: the summary
+pane, and the job listing pane, which are described in detail below.
+
+
+OPTIONS
+=======
+
+.. option:: -h, --help
+
+ Summarize available options.
+
+.. option:: --color[=WHEN]
+
+ Colorize output. The optional argument *WHEN* can be *auto*, *never*,
+ or *always*. If *WHEN* is omitted, it defaults to *always*. The default
+ value when the :option:`--color` option is not used is *auto*.
+
+.. option:: -q, --queue=NAME
+
+ Limit status and jobs to specific queue.
+
+
+KEYS
+====
+
+:program:`flux top` responds to the following key presses:
+
+j, down-arrow
+ Move cursor down in the job listing.
+
+k, up-arrow
+ Move cursor up in the job listing.
+
+h/l, left-arrow/right-arrow
+ Rotate through all queues on the system.
+
+d
+ Toggle display of inactive job details (failed vs successful jobs).
+
+enter
+ Open the job at the current cursor position. Only Flux instances (colored
+ blue in the job listing) owned by the user running :program:`flux top` may
+ be opened. The display changes to show a new Flux instance, with its jobid
+ added to the path in the summary pane. Nothing happens if the selected
+ job cannot be opened.
+
+q
+ Quit the current Flux instance, popping back to the previous Flux instance,
+ if any. If the original Flux instance is being displayed, quit the program.
+
+control-l
+ Force a redraw of the :program:`flux top` window.
+
+
+SUMMARY PANE
+============
+
+The summary pane shows the following information:
+
+- The path of nested job ID's, if navigating the job hierarchy with the *up*,
+ *down*, *enter*, and *q* keys.
+
+- The amount of time until the job's expiration time, in Flux Standard Duration
+ format. If the expiration time is unknown, the infinity symbol is
+ displayed (see `CAVEATS`_ below).
+
+- The nodes bargraph, which shows the fraction of used and down/excluded nodes
+ vs total nodes. The graph of used nodes is colored yellow and extends from
+ left to right. The graph of down/excluded nodes is red and extends from
+ right to left.
+
+- The cores bargraph, with the same layout as the nodes bargraph.
+
+- The gpus bargraph, with the same layout as the nodes bargraph.
+
+- The number of pending, running, and inactive jobs. When executed as the
+ instance owner, inactive jobs are split into completed (successful) and
+ failed (unsuccessful and canceled) jobs. This display can be toggled with
+ the ``d`` key.
+
+- A heart icon that appears each time the instance heartbeat event is
+ published.
+
+- The instance size. This is the total number of brokers, which is usually
+ also the number of nodes.
+
+- The Flux instance depth, if greater than zero. If the Flux instance was
+ not launched as a job within another Flux instance, the depth is zero.
+
+- The elapsed time the Flux instance has been running, in RFC 23 Flux Standard
+ Duration format.
+
+- The flux-core software version.
+
+
+JOB LIST PANE
+=============
+
+The job listing pane shows running jobs, that is, jobs in *RUN* (R) or
+*CLEANUP* (C) state. Jobs that are Flux instances are shown in blue and
+may be selected for display, as described in the KEYS section.
+
+The columns of output are currently fixed, and use the same naming convention
+as :man1:`flux-jobs`.
+
+The newest jobs are shown at the top of the display.
+
+:program:`flux top` subscribes to job state update events, and tries to update
+its display within 2s of receiving new job information.
+
+
+CAVEATS
+=======
+
+:program:`flux top` employs a few UTF-8 characters to maximize cuteness. If
+your heart emoji looks like a cartoon expletive, consult your system
+administrator.
+
+The infinity symbol in the expiration field does not really mean the Flux
+instance will run forever. The field width of the timestamp portion of the
+Flux Locally Unique IDs (RFC 19) used for job IDs places an outer bound on
+a Flux instance's lifetime of about 35 years.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_19`
+
+:doc:`rfc:spec_23`
+
+
+SEE ALSO
+========
+
+:man1:`flux-resource`, :man1:`flux-uptime`, :man1:`flux-jobs`, :man1:`flux-uri`
diff --git a/doc/man1/flux-update.rst b/doc/man1/flux-update.rst
new file mode 100644
index 000000000000..bb6022aeb991
--- /dev/null
+++ b/doc/man1/flux-update.rst
@@ -0,0 +1,152 @@
+.. flux-help-section: jobs
+
+==============
+flux-update(1)
+==============
+
+SYNOPSIS
+========
+
+**flux** **update** [*OPTIONS*] JOBID KEY=VALUE [KEY=VALUE...]
+
+DESCRIPTION
+===========
+
+.. program:: flux update
+
+:program:`flux update` requests an update of one or more attributes for an
+active (pending or running) job. Updates are permitted and validated by the job
+manager before being applied to the job.
+
+Keys are expressed as period-delimited strings corresponding to an attribute
+path in jobspec. If a key does not start with ``attributes.``, ``tasks.``,
+or ``.resources`` (the top-level jobspec keys allowed by RFC 14), then
+the key is assumed to be prefixed with ``attributes.system.``, such that::
+
+ $ flux update f12345 myattr="value"
+
+would request an update of ``attributes.system.myattr`` to the string value
+``"value"``.
+
+The :program:`flux update` command may also support other convenient key
+aliases. Key aliases are listed in the `SPECIAL KEYS`_ section below.
+
+Updates will be sent to the job manager update service, which checks that
+the current user is permitted to apply all updates, and that all updates
+are valid. If multiple updates are specified on the command line, then
+all updates are either applied or the request fails.
+
+.. note::
+ Job updates are allowed in the job manager by special plugins on
+ a case by case basis. At this time, the set of keys that can actually
+ be updated for a job may be very limited.
+
+The instance owner may be allowed to update specific attributes of jobs
+and bypass validation checks. For example, the duration of a guest job may
+be increased beyond currently configured limits if the update request is
+performed by the instance owner. When a job is modified in this way, future
+updates to the job by the guest user are denied with an error message::
+
+ job is immutable due to previous instance owner update
+
+This is necessary to prevent possible unintended bypass of limits or
+other checks on a job by a guest.
+
+The :program:`flux update` command may also support special handling of values
+for specific keys. Those special cases are documented in the SPECIAL KEYS
+section below.
+
+OPTIONS
+=======
+
+.. option:: -n, --dry-run
+
+ Do not send update to job manager, but print the updates in JSON to
+ stdout.
+
+.. option:: -v, --verbose
+
+ Print updated keys on success.
+
+SPECIAL KEYS
+============
+
+*attributes.system.duration*, *duration*
+ Updates of the job ``duration`` can take the form of of *[+-]FSD*, where
+ ``+`` or ``-`` indicate an adjustment of the existing duration, and *FSD*
+ is any string or number in RFC 23 Flux Standard Duration. Examples include
+ ``60``, ``1m``, ``1.5h``, ``+10m``, ``-1h``. Updates to the duration of
+ a running job may be allowed (instance owner only) and are handled as a
+ special case. For details see `DURATION UPDATE OF A RUNNING JOB`_ below.
+
+*attributes.system.queue*, *queue*
+ Updates of a pending job's ``queue`` to another enabled queue may
+ be allowed. The update could be rejected if the new job exceeds the
+ destination queue limits or if the job would not be feasible in the
+ new queue.
+
+*name*
+ Alias for job name, i.e. ``attributes.system.job.name``
+
+
+DURATION UPDATE OF A RUNNING JOB
+================================
+
+As a special case, an update of the duration of a running job may be allowed
+when performed by the instance owner and validated by the scheduler. When
+a running job's duration is updated, this triggers a ``resource-update``
+event in the main eventlog which contains the updated resource set
+(R) expiration time. This event then triggers the following actions to
+propagate the updated job expiration through the system:
+
+ - The updated expiration is forwarded to the job execution system which
+ modifies its expiration timer for the job.
+ - If the user enabled the job shell option to signal a job before the
+ time limit, then the job shell receives the updated R and resets this
+ timer.
+ - If the job is a subinstance of Flux (e.g. started with :man1:`flux-alloc`
+ or :man1:`flux-batch`), the instance resource module also receives
+ notification of the updated R, replaces its internal copy, writes
+ the update to ``resource.R`` in the KVS, and issues a ``resource-update``
+ event to the ``resource.eventlog``.
+ - The ``resource-update`` event in the eventlog results in a new
+ RFC 28 ``resource.acquire`` response to the scheduler containing the
+ updated expiration.
+ - The instance scheduler accepts the new response and updates its
+ internal resource set representation.
+ - The update service in the job-manager is notified of the R update,
+ and if the expiration has been increased, it walks the list of running
+ jobs and issues a ``resource-update`` event for any job which had
+ its expiration set based on the previous instance expiration.
+ - For any job that has its expiration extended due to an instance expiration
+ update, all these steps are repeated.
+
+EXIT STATUS
+===========
+
+0
+ All updates were successful
+
+1
+ Updates were invalid or not permitted, or the provided JOBID was invalid
+ or inactive, or the user does not have permission to modify the job
+
+2
+ Syntax or other command line error
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_14`
+
+
+SEE ALSO
+========
+
+:man1:`flux-jobs`, :man1:`flux-submit`, :man1:`flux-bulksubmit`
diff --git a/doc/man1/flux-uptime.rst b/doc/man1/flux-uptime.rst
new file mode 100644
index 000000000000..d558fdf5ea5b
--- /dev/null
+++ b/doc/man1/flux-uptime.rst
@@ -0,0 +1,95 @@
+.. flux-help-description: Tell how long Flux has been up and running
+.. flux-help-section: instance
+
+==============
+flux-uptime(1)
+==============
+
+
+SYNOPSIS
+========
+
+**flux** **uptime**
+
+
+DESCRIPTION
+===========
+
+The :program:`flux uptime` command displays the following information about the
+current Flux instance, on one or two lines:
+
+- The current wall clock time.
+
+- The broker state. See BROKER STATES.
+
+- The elapsed time the Flux instance has been running, in RFC 23 Flux Standard
+ Duration format. If the local broker is not in **run** state, the elapsed
+ time in the current state is reported instead.
+
+- The Flux instance owner. On a system instance, this is probably the
+ ``flux`` user.
+
+- The Flux instance depth. If the Flux instance was not launched as a job
+ within another Flux instance, the depth is zero.
+
+- The instance size. This is the total number of brokers, which is usually
+ also the number of nodes.
+
+- The number of drained nodes, if greater than zero. Drained nodes are
+ not eligible to run new jobs, although they may be online, and may currently
+ be running a job.
+
+- The number of offline nodes, if greater than zero. A node is offline if
+ its broker is not connected to the instance overlay network.
+
+- A notice if job submission is disabled on all queues.
+
+- A notice if scheduling is disabled.
+
+
+BROKER STATES
+=============
+
+join
+ The local broker is trying to connect to its overlay network parent,
+ or is waiting for the parent to complete initialization and reach
+ **quorum** state.
+
+init
+ The local broker is waiting for the ``rc1`` script to complete locally.
+
+quorum
+ All brokers are waiting for a configured number of brokers to reach
+ **quorum** state. The default quorum is the instance size. A Flux
+ system instance typically defines the quorum size to 1.
+
+run
+ Flux is fully up and running.
+
+cleanup
+ Cleanup scripts are executing. This state appears on the rank 0 broker only.
+
+shutdown
+ The local broker is waiting for its overlay network children to finalize
+ and disconnect.
+
+finalize
+ The local broker is waiting for the ``rc3`` script to complete locally.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_23`
+
+
+SEE ALSO
+========
+
+:man1:`flux-resource`, :man1:`flux-getattr`, :man7:`flux-broker-attributes`
diff --git a/doc/man1/flux-uri.rst b/doc/man1/flux-uri.rst
new file mode 100644
index 000000000000..c12dd9854b08
--- /dev/null
+++ b/doc/man1/flux-uri.rst
@@ -0,0 +1,180 @@
+===========
+flux-uri(1)
+===========
+
+
+SYNOPSIS
+========
+
+**flux** *uri* [OPTIONS] *TARGET*
+
+DESCRIPTION
+===========
+
+.. program:: flux uri
+
+Connections to Flux are established via a Uniform Resource Identifier
+(URI) which is passed to the :man3:`flux_open` API call. These *native*
+URIs indicate the "connector" which will be used to establish the
+connection, and are typically either *local*, with a ``local`` URI
+scheme, or *remote*, with a ``ssh`` URI scheme. These URIs are considered
+fully-resolved, native Flux URIs.
+
+Processes running within a Flux instance will have the :envvar:`FLUX_URI`
+environment variable set to a native URI which :man3:`flux_open` will
+use by default, with fallback to a compiled-in native URI for the system
+instance of Flux. Therefore, there is usually no need to specify a URI when
+connecting to the enclosing instance. However, connecting to a *different*
+Flux instance will require discovery of the fully-resolved URI for that
+instance.
+
+:program:`flux uri` attempts to resolve its *TARGET* argument to a native local
+or remote URI. The *TARGET* is itself a URI which specifies the method
+to use in URI resolution via the scheme part, with the path and query
+parts passed to a plugin which implements the resolution method.
+
+As a convenience, if *TARGET* is specified with no scheme, then the scheme
+is assumed to be ``jobid``. This allows :program:`flux uri` to be used to look
+up the URI for a Flux instance running as a job in the current enclosing
+instance with:
+
+::
+
+ $ flux uri JOBID
+
+Depending on the *TARGET* URI scheme and corresponding plugin, specific
+query arguments in *TARGET* may be supported. However, as a convenience,
+all *TARGET* URIs support the special query arguments ``local`` or
+``remote`` to force the resulting URI into a local (``local://``) or remote
+(``ssh://``) form. For example:
+
+::
+
+ $ flux uri JOBID?local
+
+would return the ``local://`` URI for *JOBID* (if the URI can be resolved).
+
+A special environment variable :envvar:`FLUX_URI_RESOLVE_LOCAL` will force
+:program:`flux uri` to always resolve URIs to local form. This is often useful
+if the local connector is known to be on the local system (i.e. within a test
+Flux instance), and ssh to localhost does not work.
+
+A list of supported URI schemes will be listed at the bottom of
+:option:`flux uri --help` message. For a description of the URI resolver
+schemes included with Flux, see the URI SCHEMES and EXAMPLES sections below.
+
+OPTIONS
+=======
+
+.. option:: --remote
+
+ Return the *remote* (``ssh://``) equivalent of the resolved URI.
+
+.. option:: --local
+
+ Return the *local* (``local://``) equivalent of the resolved URI.
+ Warning: the resulting URI may be invalid for the current system
+ if the network host specified by an :program:`ssh` URI is not the current
+ host.
+
+.. option:: --wait
+
+ Wait for the URI to become available if the resolver scheme supports it.
+ This is the same as specifying :command:`flux uri TARGET?wait`. Currently
+ only supported by the ``jobid`` resolver. It will be ignored by other
+ schemes.
+
+URI SCHEMES
+===========
+
+The following URI schemes are included by default:
+
+jobid:ID[/ID...]
+ This scheme attempts to get the URI for a Flux instance running as a
+ job in the current enclosing instance. This is the assumed scheme if no
+ ``scheme:`` is provided in *TARGET* passed to :program:`flux uri`, so the
+ ``jobid:`` prefix is optional. A hierarchy of Flux jobids is supported,
+ so ``f1234/f3456`` will resolve the URI for job ``f3456`` running in
+ job ``f1234`` in the current instance. This scheme will raise an error
+ if the target job is not running.
+
+ The ``jobid`` scheme supports the optional query parameter ``?wait``, which
+ causes the resolver to wait until a URI has been posted to the job eventlog
+ for the target jobs(s), if the job is in RUN state or any previous state.
+ Note that the resolver could wait until the job is inactive if the ``?wait``
+ query parameter is used on a job that is not an instance of Flux.
+
+pid:PID
+ This scheme attempts to read the :envvar:`FLUX_URI` value from the
+ process id *PID* using ``/proc/PID/environ``. If *PID* refers to a
+ :program:`flux-broker`, then the scheme reads :envvar:`FLUX_URI` from the
+ broker's initial program or another child process since :envvar:`FLUX_URI`
+ in the broker's environment would refer to *its* parent (or may not be
+ set at all in the case of a test instance started with :option:`flux
+ start --test-size=N`).
+
+slurm:JOBID
+ This scheme makes a best-effort to resolve the URI of a Flux instance
+ launched under Slurm. It invokes :program:`srun` to run :program:`scontrol
+ listpids` on the first node of the job, and then uses the ``pid``
+ resolver until it finds a valid :envvar:`FLUX_URI`.
+
+
+EXAMPLES
+========
+
+To get the URI of a job in the current instance in its ``local://`` form:
+
+::
+
+ $ flux uri --local ÆN8Pz2xVu
+ local:///tmp/flux-zbVtVg/jobtmp-0-ÆN8Pz2xVu/flux-59uf5w/local-0
+
+or
+
+::
+
+ $ flux uri ÆN8Pz2xVu?local
+ local:///tmp/flux-zbVtVg/jobtmp-0-ÆN8Pz2xVu/flux-59uf5w/local-0
+
+
+Get the URI of a nested job:
+
+::
+
+ $ flux uri ÆqxxTiZBM/Ær2XFWP?local
+ local:///tmp/flux-zbVtVg/jobtmp-0-ÆqxxTiZBM/flux-EPgSwk/local-0
+
+.. note::
+ With the ``jobid`` resolver, ``?local`` only needs to be placed on
+ the last component of the jobid "path" or hierarchy. This will resolve
+ each URI in turn as a local URI.
+
+Get the URI of a local flux-broker
+
+::
+
+ $ flux uri pid:$(pidof -s flux-broker)
+ local:///tmp/flux-sLuBkZ/local-0
+
+The following submits a batch job and returns the instance URI once it is
+available. Without the :option:`--wait` flag, :command:`flux uri` would fail
+immediately with "job is not running":
+
+::
+
+ $ flux uri --wait $(flux batch -n1 --wrap flux run myprogram)
+
+
+Get the URI for a Flux instance running as a Slurm job:
+
+::
+
+ $ flux uri slurm:7843494
+ ssh://cluster42/var/tmp/user/flux-MpnytT/local-0
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
diff --git a/doc/man1/flux-user.adoc b/doc/man1/flux-user.adoc
deleted file mode 100644
index f7fa32253e38..000000000000
--- a/doc/man1/flux-user.adoc
+++ /dev/null
@@ -1,76 +0,0 @@
-// flux-help-include: true
-FLUX-USER(1)
-============
-:doctype: manpage
-
-
-NAME
-----
-flux-user - Flux user database client
-
-
-SYNOPSIS
---------
-*flux* *user* 'COMMAND' ['OPTIONS']
-
-
-DESCRIPTION
------------
-The Flux user database is used to authorize users to access the
-Flux instance with assigned roles, as described in Flux RFC 12.
-
-This command line client can be used to manipulate the database.
-
-If the 'userdb' module is loaded with the '--default-rolemask'
-option, then users are added to the user database when they successfully
-authenticate to a Flux connector. Otherwise, users that are not
-already present in the database are denied access.
-
-COMMANDS
---------
-*list*::
-List the contents of the user database. Each entry is listed with
-fields separated by colons. The first field is the 32-bit userid
-in decimal. The second field is the 32-bit rolemask, represented as
-a comma-delimited list of strings.
-
-*lookup* 'USERID'::
-Look up 'USERID' in the user database and display its entry,
-as described above. If any part of 'USERID' is non-numeric,
-an attempt is made to look up 'USERID' as a name in the password file.
-If successful, the resulting UID is used in the query.
-
-*addrole* 'USERID' 'ROLEMASK'::
-Request that the database add the roles in 'ROLEMASK' to the existing
-roles held by 'USERID'. If 'USERID' has no entry in the database,
-one is added. If any part of 'USERID' is non-numeric, an attempt is
-made to look up 'USERID' as a name in the password file and use the UID
-from the result. 'ROLEMASK' may be numeric (any base - use strtoul base
-prefix rules), or may be a comma-separated list of roles, e.g.
-"owner", "user", etc..
-
-*delrole* 'USERID' 'ROLEMASK'::
-Request that the database remove the roles in 'ROLEMASK' from the existing
-roles held by 'USERID'. If after removing those roles, 'USERID' has no
-roles, the entry is removed from the database. 'USERID' and 'ROLEMASK'
-may be specified as described above.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-https://github.com/flux-framework/rfc/blob/master/spec_12.adoc[RFC 12: Flux Security Architecture]
-
diff --git a/doc/man1/flux-version.adoc b/doc/man1/flux-version.adoc
deleted file mode 100644
index d68e1e268760..000000000000
--- a/doc/man1/flux-version.adoc
+++ /dev/null
@@ -1,39 +0,0 @@
-// flux-help-description : Display flux version information
-FLUX-VERSION(1)
-===============
-:doctype: manpage
-
-
-NAME
-----
-flux-version - Display flux version information
-
-
-SYNOPSIS
---------
-*flux* *version*
-
-
-DESCRIPTION
------------
-flux-version(1) prints version information for flux components.
-At a minimum, the version of flux commands and the currently linked
-libflux-core.so library is displayed. If running within an instance,
-the version of the flux-broker found and FLUX_URI are also included.
-Finally, if flux is compiled against flux-security, then the version
-of the currently linked libflux-security is included.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
diff --git a/doc/man1/flux-version.rst b/doc/man1/flux-version.rst
new file mode 100644
index 000000000000..ec5a5372362d
--- /dev/null
+++ b/doc/man1/flux-version.rst
@@ -0,0 +1,28 @@
+.. flux-help-description : Display flux version information
+
+===============
+flux-version(1)
+===============
+
+
+SYNOPSIS
+========
+
+**flux** **version**
+
+
+DESCRIPTION
+===========
+
+:program:`flux version` prints version information for flux components.
+At a minimum, the version of flux commands and the currently linked
+libflux-core.so library is displayed. If running within an instance,
+the version of the flux-broker found and :envvar:`FLUX_URI` are also included.
+Finally, if flux is compiled against flux-security, then the version
+of the currently linked libflux-security is included.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
diff --git a/doc/man1/flux-watch.rst b/doc/man1/flux-watch.rst
new file mode 100644
index 000000000000..e1283024c623
--- /dev/null
+++ b/doc/man1/flux-watch.rst
@@ -0,0 +1,101 @@
+.. flux-help-section: jobs
+
+=============
+flux-watch(1)
+=============
+
+
+SYNOPSIS
+========
+
+**flux** **watch** [*OPTIONS*] [JOBID ...]
+
+DESCRIPTION
+===========
+
+.. program:: flux watch
+
+The :program:`flux watch` command is used to monitor the output and state of
+one or more Flux jobs. The command works similarly to the
+:option:`flux submit --watch` option, but can be used to monitor even inactive
+jobs. For example, to copy all job output to the terminal after submitting a
+series of jobs with :man1:`flux-submit` or :man1:`flux-bulksubmit`, use
+
+::
+
+ flux watch --all
+
+This command can also be used at the end of a batch script to wait for all
+submitted jobs to complete and copy all output to the same location as the
+batch job.
+
+OPTIONS
+=======
+
+.. option:: -a, --active
+
+ Watch all active jobs.
+ This is equivalent to *--filter=pending,running*.
+
+.. option:: -A, --all
+
+ Watch all jobs. This is equivalent to *--filter=pending,running,inactive*.
+
+.. option:: -c, --count=N
+
+ Limit output to N jobs (default 1000). This is a safety measure to
+ protect against watching too many jobs with the :option:`--all` option. The
+ limit can be disabled with :option:`--count=0`.
+
+.. option:: --since=WHEN
+
+ Limit output to jobs that have been active since a given timestamp.
+ This option implies :option:`-a` if no other :option:`--filter` options are
+ specified. If *WHEN* begins with ``-`` character, then the remainder is
+ considered to be a an offset in Flux standard duration (RFC 23). Otherwise,
+ any datetime expression accepted by the Python `parsedatetime
+ `_ module is accepted. Examples:
+ "-6h", "-1d", "yesterday", "2021-06-21 6am", "last Monday", etc. It is
+ assumed to be an error if a timestamp in the future is supplied.
+
+.. option:: -f, --filter=STATE|RESULT
+
+ Watch jobs with specific job state or result. Multiple states or results
+ can be listed separated by comma. See the JOB STATUS section in the
+ :man1:`flux-jobs` manual for additional information.
+
+.. option:: --progress
+
+ Display a progress bar showing the completion progress of monitored
+ jobs. Jobs that are already inactive will immediately have their
+ progress updated in the progress bar, with output later copied to the
+ terminal. The progress bar by default includes a count of pending,
+ running, complete and failed jobs, and an elapsed timer. The elapsed
+ timer is initialized at the submit time of the earliest job, or the
+ starttime of the instance with :option:`--all`, in order to reflect the real
+ elapsed time for the jobs being monitored.
+
+.. option:: --jps
+
+ With :option:`--progress`, display throughput statistics (job/s) in the
+ progress bar instead of an elapsed timer. Note: The throughput will be
+ calculated based on the elapsed time as described in the description
+ of the :option:`-progress` option.
+
+EXIT STATUS
+===========
+
+The exit status of :program:`flux watch` is 0 if no jobs match the job
+selection options or if all jobs complete with success. Otherwise, the command
+exits with the largest exit status of all monitored jobs, or 2 if there is an
+error during option processing.
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+SEE ALSO
+========
+
+:man1:`flux-jobs`, :man1:`flux-submit`, :man1:`flux-bulksubmit`
diff --git a/doc/man1/flux.adoc b/doc/man1/flux.adoc
deleted file mode 100644
index 580ca470c981..000000000000
--- a/doc/man1/flux.adoc
+++ /dev/null
@@ -1,102 +0,0 @@
-FLUX(1)
-=======
-:doctype: manpage
-
-
-NAME
-----
-flux - the Flux resource management framework
-
-
-SYNOPSIS
---------
-*flux* ['OPTIONS'] 'CMD' ['CMD-OPTIONS']
-
-
-DESCRIPTION
------------
-Flux is a modular framework for resource management.
-
-flux(1) is a front end for Flux sub-commands.
-"flux -h" summarizes the core Flux commands.
-"flux help 'CMD'" displays the manual page for 'CMD'.
-
-If 'CMD' contains a slash "/" character, it is executed directly,
-bypassing the sub-command search path.
-
-
-OPTIONS
--------
-*-h, --help*::
-Display help on options, and a list of the core Flux sub-commands.
-
-*-p, --parent*::
-If current instance is a child, connect to parent instead. Also sets
-'FLUX_KVS_NAMEPSACE' if current instance is confined to a KVS namespace
-in the parent. This option may be specified multiple times.
-
-*-v, --verbose*::
-Display command environment, and the path search for 'CMD'.
-
-*-V, --version*::
-Convenience option to run flux-version(1).
-
-
-SUB-COMMAND ENVIRONMENT
------------------------
-flux(1) uses compiled-in install paths and its environment
-to construct the environment for sub-commands.
-
-Sub-command search path::
-Look for "flux-'CMD'" executable by searching a path constructed
-with the following prototype:
-
- [getenv FLUX_EXEC_PATH_PREPEND]:install-path:\
- [getenv FLUX_EXEC_PATH]
-
-setenv FLUX_MODULE_PATH::
-Set up broker comms module search path according to:
-
- [getenv FLUX_MODULE_PATH_PREPEND]:install-path:\
- [getenv FLUX_MODULE_PATH]
-
-setenv FLUX_CONNECTOR_PATH::
-Set up search path for connector modules used by libflux to open a connection
-to the broker
-
- [getenv FLUX_CONNECTOR_PATH_PREPEND]:install-path:\
- [getenv FLUX_CONNECTOR_PATH]
-
-setenv FLUX_SEC_DIRECTORY::
-Set directory for Flux CURVE keys. This is not a search path.
-If unset, flux(1) sets it to $HOME/flux.
-
-setenv LUA_PATH::
-Set Lua module search path:
-
- [getenv FLUX_LUA_PATH_PREPEND];[getenv LUA_PATH];install-path;;;
-
-setenv LUA_CPATH::
-Set Lua binary module search path:
-
- [getenv FLUX_LUA_CPATH_PREPEND];[getenv LUA_CPATH];install-path;;;
-
-setenv PYTHONPATH::
-Set Python module search path:
-
- [getenv FLUX_PYTHONPATH_PREPEND]:[getenv PYTHONPATH];install-path
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
diff --git a/doc/man1/flux.rst b/doc/man1/flux.rst
new file mode 100644
index 000000000000..dd6fd831e168
--- /dev/null
+++ b/doc/man1/flux.rst
@@ -0,0 +1,86 @@
+=======
+flux(1)
+=======
+
+
+SYNOPSIS
+========
+
+**flux** [*OPTIONS*] *CMD* [*CMD-OPTIONS*]
+
+
+DESCRIPTION
+===========
+
+.. program:: flux
+
+Flux is a modular framework for resource management.
+
+:program:`flux` is a front end for Flux sub-commands.
+:option:`flux -h` summarizes the core Flux commands.
+:program:`flux help CMD` displays the manual page for *CMD*.
+
+If *CMD* contains a slash "/" character, it is executed directly,
+bypassing the sub-command search path.
+
+
+OPTIONS
+=======
+
+.. option:: -h, --help
+
+ Display help on options, and a list of the core Flux sub-commands.
+
+.. option:: -p, --parent
+
+ If current instance is a child, connect to parent instead. Also sets
+ :envvar:`FLUX_KVS_NAMESPACE` if current instance is confined to a KVS
+ namespace in the parent. This option may be specified multiple times.
+
+.. option:: -v, --verbose
+
+ Display command environment, and the path search for *CMD*.
+
+.. option:: -V, --version
+
+ Convenience option to run :man1:`flux-version`.
+
+
+SUB-COMMAND ENVIRONMENT
+=======================
+
+:program:`flux` uses compiled-in install paths and its environment
+to construct the environment for sub-commands. More detail is available in the
+:man7:`flux-environment` :ref:`sub_command_environment` section. A summary
+is provided below:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Name
+ - Description
+
+ * - :envvar:`FLUX_EXEC_PATH`
+ - where to look for "flux-*CMD*" executables
+
+ * - :envvar:`FLUX_MODULE_PATH`
+ - directories to look for broker modules
+
+ * - :envvar:`FLUX_CONNECTOR_PATH`
+ - directories to search for connector modules
+
+ * - :envvar:`LUA_PATH`
+ - Lua module search path
+
+ * - :envvar:`LUA_CPATH`
+ - Lua binary module search path
+
+ * - :envvar:`PYTHONPATH`
+ - Python module search path:
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
diff --git a/doc/man1/index.rst b/doc/man1/index.rst
new file mode 100644
index 000000000000..f2f7986077af
--- /dev/null
+++ b/doc/man1/index.rst
@@ -0,0 +1,10 @@
+.. _man-commands:
+
+Section 1 - Flux Commands
+=========================
+
+.. toctree::
+ :maxdepth: 1
+ :glob:
+
+ *
diff --git a/doc/man3/COPYRIGHT.adoc b/doc/man3/COPYRIGHT.adoc
deleted file mode 100644
index 6b2304f95801..000000000000
--- a/doc/man3/COPYRIGHT.adoc
+++ /dev/null
@@ -1,4 +0,0 @@
-Copyright 2014 Lawrence Livermore National Security, LLC
-and Flux developers.
-
-SPDX-License-Identifier: LGPL-3.0
diff --git a/doc/man3/JSON_PACK.adoc b/doc/man3/JSON_PACK.adoc
deleted file mode 100644
index 2860e3bccd2d..000000000000
--- a/doc/man3/JSON_PACK.adoc
+++ /dev/null
@@ -1,73 +0,0 @@
-ENCODING JSON PAYLOADS
-----------------------
-
-Flux API functions that are based on Jansson's json_pack()
-accept the following tokens in their format string.
-The type in parenthesis denotes the resulting JSON type, and
-the type in brackets (if any) denotes the C type that is expected as
-the corresponding argument or arguments.
-
-*s* (string)['const char *']::
-Convert a null terminated UTF-8 string to a JSON string.
-
-*s#* (string)['const char *', 'int']::
-Convert a UTF-8 buffer of a given length to a JSON string.
-
-*s%* (string)['const char *', 'size_t']::
-Like *s#* but the length argument is of type size_t.
-
-*+* ['const char *']::
-Like *s*, but concatenate to the previous string.
-Only valid after a string.
-
-*+#* ['const char *', 'int']::
-Like *s#*, but concatenate to the previous string.
-Only valid after a string.
-
-*+%* ['const char *', 'size_t']::
-Like *+#*, but the length argument is of type size_t.
-
-*n* (null)::
-Output a JSON null value. No argument is consumed.
-
-*b* (boolean)['int']::
-Convert a C int to JSON boolean value. Zero is converted to
-_false_ and non-zero to _true_.
-
-*i* (integer)['int']::
-Convert a C int to JSON integer.
-
-*I* (integer)['int64_t']::
-Convert a C int64_t to JSON integer.
-Note: Jansson expects a json_int_t here without committing to a size,
-but Flux guarantees that this is a 64-bit integer.
-
-*f* (real)['double']::
-Convert a C double to JSON real.
-
-*o* (any value)['json_t *']::
-Output any given JSON value as-is. If the value is added to an array
-or object, the reference to the value passed to *o* is stolen by the
-container.
-
-*O* (any value)['json_t *']::
-Like *o*, but the argument's reference count is incremented. This
-is useful if you pack into an array or object and want to keep the reference
-for the JSON value consumed by *O* to yourself.
-
-*[fmt]* (array)::
-Build an array with contents from the inner format string. *fmt* may
-contain objects and arrays, i.e. recursive value building is supported.
-
-*\{fmt\}* (object)::
-Build an object with contents from the inner format string *fmt*.
-The first, third, etc. format specifier represent a key, and must be a
-string as object keys are always strings. The second, fourth, etc.
-format specifier represent a value. Any value may be an object or array,
-i.e. recursive value building is supported.
-
-Whitespace, *:* (colon) and *,* (comma) are ignored.
-
-These descriptions came from the Jansson 2.6 manual.
-
-See also: http://jansson.readthedocs.io/en/2.6/apiref.html#building-values[Jansson API: Building Values]
diff --git a/doc/man3/JSON_UNPACK.adoc b/doc/man3/JSON_UNPACK.adoc
deleted file mode 100644
index b6b9fe54fd4e..000000000000
--- a/doc/man3/JSON_UNPACK.adoc
+++ /dev/null
@@ -1,70 +0,0 @@
-DECODING JSON PAYLOADS
-----------------------
-
-Flux API functions that are based on Jansson's json_unpack()
-accept the following tokens in their format string.
-The type in parenthesis denotes the resulting JSON type, and
-the type in brackets (if any) denotes the C type that is expected as
-the corresponding argument or arguments.
-
-*s* (string)['const char *']::
-Convert a JSON string to a pointer to a null terminated UTF-8 string.
-The resulting string is extracted by using 'json_string_value()'
-internally, so it exists as long as there are still references to the
-corresponding JSON string.
-
-*n* (null)::
-Expect a JSON null value. Nothing is extracted.
-
-*b* (boolean)['int']::
-Convert a JSON boolean value to a C int, so that _true_ is converted to 1
-and _false_ to 0.
-
-*i* (integer)['int']::
-Convert a JSON integer to a C int.
-
-*I* (integer)['int64_t']::
-Convert a JSON integer to a C int64_t.
-Note: Jansson expects a json_int_t here without committing to a size,
-but Flux guarantees that this is a 64-bit integer.
-
-*f* (real)['double']::
-Convert JSON real to a C double.
-
-*F* (real)['double']::
-Convert JSON number (integer or real) to a C double.
-
-*o* (any value)['json_t *']::
-Store a JSON value, with no conversion, to a json_t pointer.
-
-*O* (any value)['json_t *']::
-Like *o*, but the JSON value's reference count is incremented.
-
-*[fmt]* (array)::
-Convert each item in the JSON array according to the inner format
-string. *fmt* may contain objects and arrays, i.e. recursive value
-extraction is supported.
-
-*\{fmt\}* (object)::
-Convert each item in the JSON object according to the inner format
-string *fmt*. The first, third, etc. format specifier represent a
-key, and must by *s*. The corresponding argument to unpack functions
-is read as the object key. The second, fourth, etc. format specifier
-represent a value and is written to the address given as the corresponding
-argument. Note that every other argument is read from and every other
-is written to. *fmt* may contain objects and arrays as values, i.e.
-recursive value extraction is supported. Any *s* representing a key
-may be suffixed with *?* to make the key optional. If the key is not
-found, nothing is extracted.
-
-*!*::
-This special format specifier is used to enable the check that all
-object and array items are accessed, on a per-value basis. It must
-appear inside an array or object as the last format specifier before
-the closing bracket or brace.
-
-Whitespace, *:* (colon) and *,* (comma) are ignored.
-
-These descriptions came from the Jansson 2.6 manual.
-
-See also: http://jansson.readthedocs.io/en/2.6/apiref.html#parsing-and-validating-values[Jansson API: Parsing and Validating Values]
diff --git a/doc/man3/Makefile.am b/doc/man3/Makefile.am
deleted file mode 100644
index 042a85a8e921..000000000000
--- a/doc/man3/Makefile.am
+++ /dev/null
@@ -1,356 +0,0 @@
-MAN3_FILES = $(MAN3_FILES_PRIMARY) $(MAN3_FILES_SECONDARY)
-
-MAN3_FILES_PRIMARY = \
- flux_open.3 \
- flux_send.3 \
- flux_recv.3 \
- flux_requeue.3 \
- flux_aux_set.3 \
- flux_flags_set.3 \
- flux_fatal_set.3 \
- flux_event_subscribe.3 \
- flux_event_publish.3 \
- flux_pollevents.3 \
- flux_msg_encode.3 \
- flux_rpc.3 \
- flux_get_rank.3 \
- flux_attr_get.3 \
- flux_get_reactor.3 \
- flux_reactor_create.3 \
- flux_fd_watcher_create.3 \
- flux_watcher_start.3 \
- flux_zmq_watcher_create.3 \
- flux_handle_watcher_create.3 \
- flux_timer_watcher_create.3 \
- flux_periodic_watcher_create.3 \
- flux_idle_watcher_create.3 \
- flux_msg_handler_create.3 \
- flux_msg_cmp.3 \
- flux_msg_handler_addvec.3 \
- flux_child_watcher_create.3 \
- flux_signal_watcher_create.3 \
- flux_stat_watcher_create.3 \
- flux_respond.3 \
- flux_reactor_now.3 \
- flux_request_decode.3 \
- flux_event_decode.3 \
- flux_response_decode.3 \
- flux_request_encode.3 \
- flux_content_load.3 \
- flux_log.3 \
- flux_future_get.3 \
- flux_future_create.3 \
- flux_future_wait_all_create.3 \
- flux_future_and_then.3 \
- flux_kvs_lookup.3 \
- flux_kvs_commit.3 \
- flux_kvs_txn_create.3 \
- flux_kvs_namespace_create.3 \
- flux_kvs_getroot.3 \
- flux_kvs_copy.3 \
- flux_core_version.3 \
- idset_create.3
-
-# These files are generated as roff .so includes of a primary page.
-# A2X handles this automatically if mentioned in NAME section
-MAN3_FILES_SECONDARY = \
- flux_clone.3 \
- flux_close.3 \
- flux_requeue_nocopy.3 \
- flux_aux_get.3 \
- flux_flags_unset.3 \
- flux_flags_get.3 \
- flux_fatal_error.3 \
- FLUX_FATAL.3 \
- flux_event_unsubscribe.3 \
- flux_event_publish_pack.3 \
- flux_event_publish_raw.3 \
- flux_event_publish_get_seq.3 \
- flux_pollfd.3 \
- flux_msg_decode.3 \
- flux_get_size.3 \
- flux_attr_set.3 \
- flux_set_reactor.3 \
- flux_reactor_destroy.3 \
- flux_reactor_run.3 \
- flux_reactor_stop.3 \
- flux_reactor_stop_error.3 \
- flux_reactor_active_incref.3 \
- flux_reactor_active_decref.3 \
- flux_fd_watcher_get_fd.3 \
- flux_watcher_stop.3 \
- flux_watcher_destroy.3 \
- flux_watcher_next_wakeup.3 \
- flux_zmq_watcher_get_zsock.3 \
- flux_handle_watcher_get_flux.3 \
- flux_timer_watcher_reset.3 \
- flux_periodic_watcher_reset.3 \
- flux_prepare_watcher_create.3 \
- flux_check_watcher_create.3 \
- flux_msg_handler_destroy.3 \
- flux_msg_handler_start.3 \
- flux_msg_handler_stop.3 \
- flux_msg_handler_delvec.3 \
- flux_child_watcher_get_rpid.3 \
- flux_child_watcher_get_rstatus.3 \
- flux_signal_watcher_get_signum.3 \
- flux_stat_watcher_get_rstat.3 \
- flux_respond_raw.3 \
- flux_respond_pack.3 \
- flux_respond_error.3 \
- flux_reactor_now_update.3 \
- flux_request_unpack.3 \
- flux_request_decode_raw.3 \
- flux_event_unpack.3 \
- flux_event_encode.3 \
- flux_event_pack.3 \
- flux_event_encode_raw.3 \
- flux_event_decode_raw.3 \
- flux_response_decode_raw.3 \
- flux_response_decode_error.3 \
- flux_request_encode_raw.3 \
- flux_content_load_get.3 \
- flux_content_store.3 \
- flux_content_store_get.3 \
- flux_vlog.3 \
- flux_log_set_appname.3 \
- flux_log_set_procid.3 \
- flux_future_then.3 \
- flux_future_wait_for.3 \
- flux_future_reset.3 \
- flux_future_destroy.3 \
- flux_future_get.3 \
- flux_future_fulfill.3 \
- flux_future_fulfill_error.3 \
- flux_future_fulfill_with.3 \
- flux_future_aux_set.3 \
- flux_future_aux_get.3 \
- flux_future_set_flux.3 \
- flux_future_get_flux.3 \
- flux_future_wait_all_create.3 \
- flux_future_wait_any_create.3 \
- flux_future_push.3 \
- flux_future_first_child.3 \
- flux_future_next_child.3 \
- flux_future_get_child.3 \
- flux_future_and_then.3 \
- flux_future_or_then.3 \
- flux_future_continue.3 \
- flux_future_continue_error.3 \
- flux_rpc_pack.3 \
- flux_rpc_raw.3 \
- flux_rpc_message.3 \
- flux_rpc_get.3 \
- flux_rpc_get_unpack.3 \
- flux_rpc_get_raw.3 \
- flux_kvs_lookupat.3 \
- flux_kvs_lookup_get.3 \
- flux_kvs_lookup_get_unpack.3 \
- flux_kvs_lookup_get_raw.3 \
- flux_kvs_lookup_get_dir.3 \
- flux_kvs_lookup_get_treeobj.3 \
- flux_kvs_lookup_get_symlink.3 \
- flux_kvs_getroot_get_treeobj.3 \
- flux_kvs_getroot_get_blobref.3 \
- flux_kvs_getroot_get_sequence.3 \
- flux_kvs_getroot_get_owner.3 \
- flux_kvs_getroot_cancel.3 \
- flux_kvs_fence.3 \
- flux_kvs_commit_get_treeobj.3 \
- flux_kvs_commit_get_sequence.3 \
- flux_kvs_txn_destroy.3 \
- flux_kvs_txn_put.3 \
- flux_kvs_txn_pack.3 \
- flux_kvs_txn_vpack.3 \
- flux_kvs_txn_mkdir.3 \
- flux_kvs_txn_unlink.3 \
- flux_kvs_txn_symlink.3 \
- flux_kvs_txn_put_raw.3 \
- flux_kvs_namespace_remove.3 \
- flux_kvs_move.3 \
- flux_core_version_string.3 \
- idset_destroy.3 \
- idset_encode.3 \
- idset_decode.3 \
- idset_set.3 \
- idset_clear.3 \
- idset_first.3 \
- idset_next.3 \
- idset_count.3
-
-ADOC_FILES = $(MAN3_FILES_PRIMARY:%.3=%.adoc)
-XML_FILES = $(MAN3_FILES_PRIMARY:%.3=%.xml)
-
-if ENABLE_DOCS
-dist_man_MANS = $(MAN3_FILES)
-$(MAN3_FILES): COPYRIGHT.adoc JSON_PACK.adoc JSON_UNPACK.adoc
-endif
-
-SUFFIXES = .adoc .3
-
-STDERR_DEVNULL = $(stderr_devnull_$(V))
-stderr_devnull_ = $(stderr_devnull_$(AM_DEFAULT_VERBOSITY))
-stderr_devnull_0 = 2>/dev/null
-
-.adoc.3:
- $(AM_V_GEN)$(ADOC) --attribute mansource=$(PACKAGE_NAME) \
- --attribute manversion=$(PACKAGE_VERSION) \
- --attribute manmanual="Flux Programming Reference" \
- --destination-dir $(builddir) \
- --doctype manpage $(ADOC_FORMAT_OPT) manpage $< $(STDERR_DEVNULL)
-
-flux_clone.3: flux_open.3
-flux_close.3: flux_open.3
-flux_requeue_nocopy.3: flux_requeue.3
-flux_aux_get.3: flux_aux_set.3
-flux_flags_unset.3: flux_flags_set.3
-flux_flags_get.3: flux_flags_set.3
-flux_fatal_error.3: flux_fatal_set.3
-FLUX_FATAL.3: flux_fatal_set.3
-flux_event_unsubscribe.3: flux_event_subscribe.3
-flux_event_publish_pack.3: flux_event_publish.3
-flux_event_publish_raw.3: flux_event_publish.3
-flux_event_publish_get_seq.3: flux_event_publish.3
-flux_pollfd.3: flux_pollevents.3
-flux_msg_decode.3: flux_msg_encode.3
-flux_get_size.3: flux_get_rank.3
-flux_attr_set.3: flux_attr_get.3
-flux_set_reactor.3: flux_get_reactor.3
-flux_reactor_destroy.3: flux_reactor_create.3
-flux_reactor_run.3: flux_reactor_create.3
-flux_reactor_stop.3: flux_reactor_create.3
-flux_reactor_error.3: flux_reactor_create.3
-flux_reactor_active_incref.3: flux_reactor_create.3
-flux_reactor_active_decref.3: flux_reactor_create.3
-flux_fd_watcher_get_fd.3: flux_fd_watcher_create.3
-flux_watcher_stop.3: flux_watcher_start.3
-flux_watcher_destroy.3: flux_watcher_start.3
-flux_watcher_next_wakeup.3: flux_watcher_start.3
-flux_zmq_watcher_get_zsock.3: flux_zmq_watcher_create.3
-flux_handle_watcher_get_flux.3: flux_handle_watcher_create.3
-flux_timer_watcher_reset.3: flux_timer_watcher_create.3
-flux_periodic_watcher_reset.3: flux_periodic_watcher_create.3
-flux_prepare_watcher_create.3: flux_idle_watcher_create.3
-flux_check_watcher_create.3: flux_idle_watcher_create.3
-flux_msg_handler_destroy.3: flux_msg_handler_create.3
-flux_msg_handler_start.3: flux_msg_handler_create.3
-flux_msg_handler_stop.3: flux_msg_handler_create.3
-flux_msg_handler_delvec.3: flux_msg_handler_addvec.3
-flux_child_watcher_get_rpid.3: flux_child_watcher_create.3
-flux_child_watcher_get_rstatus.3: flux_child_watcher_create.3
-flux_signal_watcher_get_signum.3: flux_signal_watcher_create.3
-flux_stat_watcher_get_rstat.3: flux_stat_watcher_create.3
-flux_respond_raw.3: flux_respond.3
-flux_respond_pack.3: flux_respond.3
-flux_respond_error.3: flux_respond.3
-flux_reactor_now_update.3: flux_reactor_now.3
-flux_request_unpack.3: flux_request_decode.3
-flux_request_decode_raw.3: flux_request_decode.3
-flux_event_unpack.3: flux_event_decode.3
-flux_event_encode.3: flux_event_decode.3
-flux_event_pack.3: flux_event_decode.3
-flux_event_encode_raw.3: flux_event_decode.3
-flux_event_decode_raw.3: flux_event_decode.3
-flux_response_decode_raw.3: flux_response_decode.3
-flux_response_decode_error.3: flux_response_decode.3
-flux_request_encode_raw.3: flux_request_encode.3
-flux_content_load_get.3: flux_content_load.3
-flux_content_store.3: flux_content_load.3
-flux_content_store_get.3: flux_content_load.3
-flux_vlog.3: flux_log.3
-flux_log_set_appname.3: flux_log.3
-flux_log_set_procid.3: flux_log.3
-flux_future_reset.3: flux_future_get.3
-flux_future_destroy.3: flux_future_get.3
-flux_future_wait_for.3: flux_future_get.3
-flux_future_then.3: flux_future_get.3
-flux_future_fulfill.3: flux_future_create.3
-flux_future_fulfill_error.3: flux_future_create.3
-flux_future_fulfill_with.3: flux_future_create.3
-flux_future_aux_set.3: flux_future_create.3
-flux_future_aux_get.3: flux_future_create.3
-flux_future_set_flux.3: flux_future_create.3
-flux_future_get_flux.3: flux_future_create.3
-flux_rpc_pack.3: flux_rpc.3
-flux_rpc_raw.3: flux_rpc.3
-flux_rpc_message.3: flux_rpc.3
-flux_rpc_get.3: flux_rpc.3
-flux_rpc_get_unpack.3: flux_rpc.3
-flux_rpc_get_raw.3: flux_rpc.3
-flux_kvs_lookupat.3: flux_kvs_lookup.3
-flux_kvs_lookup_get.3: flux_kvs_lookup.3
-flux_kvs_lookup_get_unpack.3: flux_kvs_lookup.3
-flux_kvs_lookup_get_raw.3: flux_kvs_lookup.3
-flux_kvs_lookup_get_dir.3: flux_kvs_lookup.3
-flux_kvs_lookup_treeobj.3: flux_kvs_lookup.3
-flux_kvs_lookup_symlink.3: flux_kvs_lookup.3
-flux_kvs_getroot_get_treeobj.3: flux_kvs_getroot.3
-flux_kvs_getroot_get_blobref.3: flux_kvs_getroot.3
-flux_kvs_getroot_get_sequence.3: flux_kvs_getroot.3
-flux_kvs_getroot_get_owner.3: flux_kvs_getroot.3
-flux_kvs_getroot_cancel.3: flux_kvs_getroot.3
-flux_kvs_fence.3: flux_kvs_commit.3
-flux_kvs_commit_get_treeobj.3: flux_kvs_commit.3
-flux_kvs_commit_get_sequence.3: flux_kvs_commit.3
-flux_kvs_txn_destroy.3: flux_kvs_txn_create.3
-flux_kvs_txn_put.3: flux_kvs_txn_create.3
-flux_kvs_txn_pack.3: flux_kvs_txn_create.3
-flux_kvs_txn_vpack.3: flux_kvs_txn_create.3
-flux_kvs_txn_mkdir.3: flux_kvs_txn_create.3
-flux_kvs_txn_unlink.3: flux_kvs_txn_create.3
-flux_kvs_txn_symlink.3: flux_kvs_txn_create.3
-flux_kvs_txn_put_raw.3: flux_kvs_txn_create.3
-# N.B. exceeds max 8 stubs flux_kvs_txn_put_treeobj.3: flux_kvs_txn_create.3
-flux_kvs_namespace_remove.3: flux_kvs_namespace_create.3
-flux_kvs_move.3: flux_kvs_copy.3
-flux_core_version_string.3: flux_core_version.3
-idset_destroy.3: idset_create.3
-idset_encode.3: idset_create.3
-idset_decode.3: idset_create.3
-idset_set.3: idset_create.3
-idset_clear.3: idset_create.3
-idset_first.3: idset_create.3
-idset_next.3: idset_create.3
-idset_count.3: idset_create.3
-# N.B. exceeds max 8 stubs idset_equal.3
-
-flux_open.3: topen.c
-flux_send.3: tsend.c
-flux_recv.3: trecv.c
-flux_event_subscribe.3: tevent.c
-flux_rpc.3: trpc.c
-flux_rpc.3: trpc_then.c
-flux_get_rank.3: tinfo.c
-
-
-
-EXTRA_DIST = $(ADOC_FILES) COPYRIGHT.adoc JSON_PACK.adoc JSON_UNPACK.adoc
-
-CLEANFILES = $(MAN3_FILES) $(XML_FILES)
-
-AM_CFLAGS = \
- $(WARNING_CFLAGS) \
- $(CODE_COVERAGE_CFLAGS)
-
-AM_LDFLAGS = \
- $(CODE_COVERAGE_LIBS)
-
-AM_CPPFLAGS = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/src/include \
- -I$(top_builddir)/src/common/libflux \
- $(ZMQ_CFLAGS) $(LIBUUID_CFLAGS)
-
-LDADD = \
- $(top_builddir)/src/common/libflux-internal.la \
- $(top_builddir)/src/common/libflux-core.la \
- $(ZMQ_LIBS) $(LIBUUID_CFLAGS) $(LIBPTHREAD)
-
-check_PROGRAMS = \
- topen \
- tsend \
- trecv \
- tevent \
- trpc \
- trpc_then \
- tinfo
diff --git a/doc/man3/common/experimental.rst b/doc/man3/common/experimental.rst
new file mode 100644
index 000000000000..00be899898a2
--- /dev/null
+++ b/doc/man3/common/experimental.rst
@@ -0,0 +1,4 @@
+Experimental Flux features and interfaces are made available for evaluation
+only and may change or be removed without notice.
+
+Feedback is welcome. Please use the flux-core project Github issue tracker.
diff --git a/doc/man3/common/json_pack.rst b/doc/man3/common/json_pack.rst
new file mode 100644
index 000000000000..b233b4d5bca9
--- /dev/null
+++ b/doc/man3/common/json_pack.rst
@@ -0,0 +1,77 @@
+Flux API functions that are based on Jansson's :func:`json_pack`
+accept the following tokens in their format string.
+The type in parenthesis denotes the resulting JSON type, and
+the type in brackets (if any) denotes the C type that is expected as
+the corresponding argument or arguments.
+
+**s** (string)['const char \*']
+ Convert a null terminated UTF-8 string to a JSON string.
+
+**s?** (string)['const char \*']
+ Like **s**, but if the argument is NULL, outputs a JSON null value.
+
+**s#** (string)['const char \*', 'int']
+ Convert a UTF-8 buffer of a given length to a JSON string.
+
+**s%** (string)['const char \*', 'size_t']
+ Like **s#** but the length argument is of type size_t.
+
+**+** ['const char \*']
+ Like **s**, but concatenate to the previous string.
+ Only valid after a string.
+
+**+#** ['const char \*', 'int']
+ Like **s#**, but concatenate to the previous string.
+ Only valid after a string.
+
+**+%** ['const char \*', 'size_t']
+ Like **+#**, but the length argument is of type size_t.
+
+**n** (null)
+ Output a JSON null value. No argument is consumed.
+
+**b** (boolean)['int']
+ Convert a C int to JSON boolean value. Zero is converted to
+ *false* and non-zero to *true*.
+
+**i** (integer)['int']
+ Convert a C int to JSON integer.
+
+**I** (integer)['int64_t']
+ Convert a C int64_t to JSON integer.
+ Note: Jansson expects a json_int_t here without committing to a size,
+ but Flux guarantees that this is a 64-bit integer.
+
+**f** (real)['double']
+ Convert a C double to JSON real.
+
+**o** (any value)['json_t \*']
+ Output any given JSON value as-is. If the value is added to an array
+ or object, the reference to the value passed to **o** is stolen by the
+ container.
+
+**O** (any value)['json_t \*']
+ Like **o**, but the argument's reference count is incremented. This
+ is useful if you pack into an array or object and want to keep the reference
+ for the JSON value consumed by **O** to yourself.
+
+**o?**, **O?** (any value)['json_t \*']
+ Like **o** and **O**, respectively, but if the argument is NULL,
+ output a JSON null value.
+
+**[fmt]** (array)
+ Build an array with contents from the inner format string. **fmt** may
+ contain objects and arrays, i.e. recursive value building is supported.
+
+**{fmt}** (object)
+ Build an object with contents from the inner format string **fmt**.
+ The first, third, etc. format specifier represent a key, and must be a
+ string as object keys are always strings. The second, fourth, etc.
+ format specifier represent a value. Any value may be an object or array,
+ i.e. recursive value building is supported.
+
+Whitespace, **:** (colon) and **,** (comma) are ignored.
+
+These descriptions came from the Jansson 2.9 manual.
+
+See also: Jansson API: Building Values: http://jansson.readthedocs.io/en/2.9/apiref.html#building-values
diff --git a/doc/man3/common/json_unpack.rst b/doc/man3/common/json_unpack.rst
new file mode 100644
index 000000000000..f3afe8b5e5cb
--- /dev/null
+++ b/doc/man3/common/json_unpack.rst
@@ -0,0 +1,71 @@
+Flux API functions that are based on Jansson's :func:`json_unpack`
+accept the following tokens in their format string.
+The type in parenthesis denotes the resulting JSON type, and
+the type in brackets (if any) denotes the C type that is expected as
+the corresponding argument or arguments.
+
+**s** (string)['const char \*']
+ Convert a JSON string to a pointer to a null terminated UTF-8 string.
+ The resulting string is extracted by using 'json_string_value()'
+ internally, so it exists as long as there are still references to the
+ corresponding JSON string.
+
+**s%** (string)['const char \*', 'size_t']
+ Convert a JSON string to a pointer to a null terminated UTF-8
+ string and its length.
+
+**n** (null)
+ Expect a JSON null value. Nothing is extracted.
+
+**b** (boolean)['int']
+ Convert a JSON boolean value to a C int, so that *true* is converted to 1
+ and *false* to 0.
+
+**i** (integer)['int']
+ Convert a JSON integer to a C int.
+
+**I** (integer)['int64_t']
+ Convert a JSON integer to a C int64_t.
+ Note: Jansson expects a json_int_t here without committing to a size,
+ but Flux guarantees that this is a 64-bit integer.
+
+**f** (real)['double']
+ Convert JSON real to a C double.
+
+**F** (real)['double']
+ Convert JSON number (integer or real) to a C double.
+
+**o** (any value)['json_t \*']
+ Store a JSON value, with no conversion, to a json_t pointer.
+
+**O** (any value)['json_t \*']
+ Like **o**, but the JSON value's reference count is incremented.
+
+**[fmt]** (array)
+ Convert each item in the JSON array according to the inner format
+ string. **fmt** may contain objects and arrays, i.e. recursive value
+ extraction is supported.
+
+**{fmt}** (object)
+ Convert each item in the JSON object according to the inner format
+ string **fmt**. The first, third, etc. format specifier represent a
+ key, and must by **s**. The corresponding argument to unpack functions
+ is read as the object key. The second, fourth, etc. format specifier
+ represent a value and is written to the address given as the corresponding
+ argument. Note that every other argument is read from and every other
+ is written to. **fmt** may contain objects and arrays as values, i.e.
+ recursive value extraction is supported. Any **s** representing a key
+ may be suffixed with **?** to make the key optional. If the key is not
+ found, nothing is extracted.
+
+**!**
+ This special format specifier is used to enable the check that all
+ object and array items are accessed, on a per-value basis. It must
+ appear inside an array or object as the last format specifier before
+ the closing bracket or brace.
+
+Whitespace, **:** (colon) and **,** (comma) are ignored.
+
+These descriptions came from the Jansson 2.9 manual.
+
+See also: Jansson API: Parsing and Validating Values: http://jansson.readthedocs.io/en/2.9/apiref.html#parsing-and-validating-values
diff --git a/doc/man3/common/resources.rst b/doc/man3/common/resources.rst
new file mode 100644
index 000000000000..dcc16e8954b0
--- /dev/null
+++ b/doc/man3/common/resources.rst
@@ -0,0 +1,5 @@
+Flux: http://flux-framework.org
+
+Flux RFC: https://flux-framework.readthedocs.io/projects/flux-rfc
+
+Issue Tracker: https://github.com/flux-framework/flux-core/issues
diff --git a/doc/man3/example/die.h b/doc/man3/example/die.h
new file mode 100644
index 000000000000..177ad83cff62
--- /dev/null
+++ b/doc/man3/example/die.h
@@ -0,0 +1,14 @@
+#ifndef _EXAMPLE_DIE
+#define _EXAMPLE_DIE
+
+#include
+#include
+#include
+
+#define die(fmt, ...) do { \
+ int _e = errno; \
+ fprintf (stderr, (fmt), ##__VA_ARGS__); \
+ fprintf (stderr, ": %s\n", strerror (_e)); \
+ exit (1); \
+} while (0);
+#endif // _EXAMPLE_DIE
diff --git a/doc/man3/example/event.c b/doc/man3/example/event.c
new file mode 100644
index 000000000000..36a29d393b2d
--- /dev/null
+++ b/doc/man3/example/event.c
@@ -0,0 +1,24 @@
+#include
+#include "die.h"
+
+int main (int argc, char **argv)
+{
+ flux_t *h;
+ flux_msg_t *msg;
+ const char *topic;
+
+ if (!(h = flux_open (NULL, 0)))
+ die ("could not connect to broker");
+ if (flux_event_subscribe (h, "heartbeat.pulse") < 0)
+ die ("error subscribing to heartbeat");
+ if (!(msg = flux_recv (h, FLUX_MATCH_EVENT, 0)))
+ die ("message receive error");
+ if (flux_msg_get_topic (msg, &topic) < 0)
+ die ("error decoding message");
+ printf ("Event: %s\n", topic);
+
+ (void)flux_event_unsubscribe (h, "heartbeat.pulse");
+ flux_msg_destroy (msg);
+ flux_close (h);
+ return (0);
+}
diff --git a/doc/man3/example/info.c b/doc/man3/example/info.c
new file mode 100644
index 000000000000..2b3ed1e12a1f
--- /dev/null
+++ b/doc/man3/example/info.c
@@ -0,0 +1,17 @@
+#include
+#include "die.h"
+
+int main (int argc, char **argv)
+{
+ flux_t *h;
+ uint32_t rank, n;
+
+ if (!(h = flux_open (NULL, 0)))
+ die ("could not connect to broker");
+ if (flux_get_rank (h, &rank) < 0)
+ die ("error getting rank");
+ if (flux_get_size (h, &n) < 0)
+ die ("error getting size");
+ flux_close (h);
+ return (0);
+}
diff --git a/doc/man3/example/open.c b/doc/man3/example/open.c
new file mode 100644
index 000000000000..a49d6555a37a
--- /dev/null
+++ b/doc/man3/example/open.c
@@ -0,0 +1,16 @@
+#include
+#include "die.h"
+
+int main (int argc, char **argv)
+{
+ flux_t *h;
+ uint32_t rank;
+
+ if (!(h = flux_open (NULL, 0)))
+ die ("could not connect to broker");
+ if (flux_get_rank (h, &rank) < 0)
+ die ("could not get rank");
+ printf ("My rank is %d\n", (int)rank);
+ flux_close (h);
+ return (0);
+}
diff --git a/doc/man3/example/recv.c b/doc/man3/example/recv.c
new file mode 100644
index 000000000000..fcf4b3ea7645
--- /dev/null
+++ b/doc/man3/example/recv.c
@@ -0,0 +1,24 @@
+#include
+#include "die.h"
+
+int main (int argc, char **argv)
+{
+ flux_t *h;
+ flux_msg_t *msg;
+ const char *topic;
+
+ if (!(h = flux_open (NULL, 0)))
+ die ("could not connect to broker");
+ if (flux_event_subscribe (h, "") < 0)
+ die ("could not subscribe to all events");
+ for (;;) {
+ if ((msg = flux_recv (h, FLUX_MATCH_EVENT, 0)))
+ die ("receive error");
+ if (flux_msg_get_topic (msg, &topic) < 0)
+ die ("message decode error");
+ printf ("Event: %s\n", topic);
+ flux_msg_destroy (msg);
+ }
+ flux_close (h);
+ return (0);
+}
diff --git a/doc/man3/example/rpc.c b/doc/man3/example/rpc.c
new file mode 100644
index 000000000000..26f032352baa
--- /dev/null
+++ b/doc/man3/example/rpc.c
@@ -0,0 +1,31 @@
+#include
+#include "die.h"
+
+int main (int argc, char **argv)
+{
+ flux_t *h;
+ flux_future_t *f;
+ const char *rankstr;
+
+ if (!(h = flux_open (NULL, 0)))
+ die ("could not connect to broker");
+
+ if (!(f = flux_rpc_pack (h,
+ "attr.get",
+ FLUX_NODEID_ANY,
+ 0,
+ "{s:s}",
+ "name", "rank")))
+ die ("error sending attr.get request");
+
+ if (flux_rpc_get_unpack (f,
+ "{s:s}",
+ "value", &rankstr) < 0)
+ die ("error fetching rank");
+
+ printf ("rank is %s\n", rankstr);
+
+ flux_future_destroy (f);
+ flux_close (h);
+ return (0);
+}
diff --git a/doc/man3/example/rpc_then.c b/doc/man3/example/rpc_then.c
new file mode 100644
index 000000000000..1a562c341935
--- /dev/null
+++ b/doc/man3/example/rpc_then.c
@@ -0,0 +1,37 @@
+#include
+#include "die.h"
+
+void continuation (flux_future_t *f, void *arg)
+{
+ const char *rankstr;
+
+ if (flux_rpc_get_unpack (f, "{s:s}", "value", &rankstr) < 0)
+ die ("error getting rank");
+
+ printf ("rank is %s\n", rankstr);
+ flux_future_destroy (f);
+}
+
+int main (int argc, char **argv)
+{
+ flux_t *h;
+ flux_future_t *f;
+
+ if (!(h = flux_open (NULL, 0)))
+ die ("could not connect to broker");
+
+ if (!(f = flux_rpc_pack (h,
+ "attr.get",
+ FLUX_NODEID_ANY,
+ 0,
+ "{s:s}",
+ "name", "rank"))
+ || flux_future_then (f, -1., continuation, NULL) < 0)
+ die ("error sending attr.get request");
+
+ if (flux_reactor_run (flux_get_reactor (h), 0) < 0)
+ die ("reactor meltdown");
+
+ flux_close (h);
+ return (0);
+}
diff --git a/doc/man3/example/send.c b/doc/man3/example/send.c
new file mode 100644
index 000000000000..9e3cc4e867ba
--- /dev/null
+++ b/doc/man3/example/send.c
@@ -0,0 +1,18 @@
+#include
+#include "die.h"
+
+int main (int argc, char **argv)
+{
+ flux_t *h;
+ flux_msg_t *msg;
+
+ if (!(h = flux_open (NULL, 0)))
+ die ("flux open %s", "NULL");
+ if (!(msg = flux_event_encode ("snack.bar.closing", NULL)))
+ die ("flux_event_encode");
+ if (flux_send (h, msg, 0) < 0)
+ die ("flux_send");
+ flux_msg_destroy (msg);
+ flux_close (h);
+ return (0);
+}
diff --git a/doc/man3/example/sync.c b/doc/man3/example/sync.c
new file mode 100644
index 000000000000..5f5c0872a389
--- /dev/null
+++ b/doc/man3/example/sync.c
@@ -0,0 +1,34 @@
+#include
+#include "die.h"
+
+const double sync_min = 1.0;
+const double sync_max = 60.0;
+
+void sync_continuation (flux_future_t *f, void *arg)
+{
+ // do work here
+ flux_future_reset (f);
+}
+
+int main (int argc, char **argv)
+{
+ flux_t *h;
+ flux_future_t *f;
+
+ if (!(h = flux_open (NULL, 0)))
+ die ("could not connect to broker");
+
+ if (!(f = flux_sync_create (h, sync_max)))
+ die ("error creating future");
+
+ if (flux_future_then (f, sync_min, sync_continuation, NULL) < 0)
+ die ("error registering continuation");
+
+ if (flux_reactor_run (flux_get_reactor (h), 0) < 0)
+ die ("reactor returned with error");
+
+ flux_future_destroy (f);
+
+ flux_close (h);
+ return (0);
+}
diff --git a/doc/man3/flux_attr_get.adoc b/doc/man3/flux_attr_get.adoc
deleted file mode 100644
index 6886530dc8b9..000000000000
--- a/doc/man3/flux_attr_get.adoc
+++ /dev/null
@@ -1,81 +0,0 @@
-flux_attr_get(3)
-================
-:doctype: manpage
-
-
-NAME
-----
-flux_attr_get, flux_attr_set - get/set Flux broker attributes
-
-
-SYNOPSIS
---------
- #include
-
- const char *flux_attr_get (flux_t *h, const char *name);
-
- int flux_attr_set (flux_t *h, const char *name, const char *val);
-
-
-DESCRIPTION
------------
-
-Flux broker attributes are both a simple, general-purpose key-value
-store with scope limited to the local broker rank, and a method for the
-broker to export information needed by Flux comms modules and utilities.
-
-`flux_attr_get()` retrieves the value of the attribute _name_.
-
-Attributes that have the broker tags as _immutable_ are cached automatically
-in the flux_t handle. For example, the "rank" attribute is a frequently
-accessed attribute whose value never changes. It will be cached on the first
-access and thereafter does not require an RPC to the broker to access.
-
-`flux_attr_set()` updates the value of attribute _name_ to _val_.
-If _name_ is not currently a valid attribute, it is created.
-If _val_ is NULL, the attribute is unset.
-
-
-RETURN VALUE
-------------
-
-`flux_attr_get()` returns the requested value on success. On error, NULL
-is returned and errno is set appropriately.
-
-`flux_attr_set()` returns zero on success. On error, -1 is returned
-and errno is set appropriately.
-
-
-ERRORS
-------
-
-ENOENT::
-The requested attribute is invalid or has a NULL value on the broker.
-
-EINVAL::
-Some arguments were invalid.
-
-EPERM::
-Set was attempted on an attribute that is not writable with the
-user's credentials.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-flux-lsattr(1), flux-getattr(1), flux-setattr(1), flux-broker-attributes(7),
-https://github.com/flux-framework/rfc/blob/master/spec_3.adoc[RFC 3: CMB1 - Flux Comms Message Broker Protocol]
diff --git a/doc/man3/flux_attr_get.rst b/doc/man3/flux_attr_get.rst
new file mode 100644
index 000000000000..c073b397fb90
--- /dev/null
+++ b/doc/man3/flux_attr_get.rst
@@ -0,0 +1,72 @@
+================
+flux_attr_get(3)
+================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ const char *flux_attr_get (flux_t *h, const char *name);
+
+ int flux_attr_set (flux_t *h, const char *name, const char *val);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+Flux broker attributes are both a simple, general-purpose key-value
+store with scope limited to the local broker rank, and a method for the
+broker to export information needed by Flux services and utilities.
+
+:func:`flux_attr_get` retrieves the value of the attribute :var:`name`.
+
+Attributes that have the broker tags as *immutable* are cached automatically
+in the :type:`flux_t` handle. For example, the "rank" attribute is a frequently
+accessed attribute whose value never changes. It will be cached on the first
+access and thereafter does not require an RPC to the broker to access.
+
+:func:`flux_attr_set` updates the value of attribute :var:`name` to :var:`val`.
+If :var:`name` is not currently a valid attribute, it is created.
+If :var:`val` is NULL, the attribute is unset.
+
+
+RETURN VALUE
+============
+
+:func:`flux_attr_get` returns the requested value on success. On error, NULL
+is returned and :var:`errno` is set appropriately.
+
+:func:`flux_attr_set` returns zero on success. On error, -1 is returned
+and errno is set appropriately.
+
+
+ERRORS
+======
+
+ENOENT
+ The requested attribute is invalid or has a NULL value on the broker.
+
+EINVAL
+ Some arguments were invalid.
+
+EPERM
+ Set was attempted on an attribute that is not writable with the
+ user's credentials.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man1:`flux-getattr`, :man7:`flux-broker-attributes`,
diff --git a/doc/man3/flux_aux_set.adoc b/doc/man3/flux_aux_set.adoc
deleted file mode 100644
index 3c7822e43ea3..000000000000
--- a/doc/man3/flux_aux_set.adoc
+++ /dev/null
@@ -1,79 +0,0 @@
-flux_aux_set(3)
-===============
-:doctype: manpage
-
-
-NAME
-----
-flux_aux_set, flux_aux_get - get/set auxiliary handle data
-
-
-SYNOPSIS
---------
- #include
-
- typedef void (*flux_free_f)(void *arg);
-
- void *flux_aux_get (flux_t *h, const char *name);
-
- int flux_aux_set (flux_t *h, const char *name,
- void *aux, flux_free_f destroy);
-
-
-DESCRIPTION
------------
-
-`flux_aux_set()` attaches application-specific data
-to the parent object _h_. It stores data _aux_ by key _name_,
-with optional destructor _destroy_. The destructor, if non-NULL,
-is called when the parent object is destroyed, or when
-_key_ is overwritten by a new value. If _aux_ is NULL,
-the destructor for a previous value, if any is called,
- but no new value is stored. If _name_ is NULL,
-_aux_ is stored anonymously.
-
-`flux_aux_get()` retrieves application-specific data
-by _name_. If the data was stored anonymously, it
-cannot be retrieved.
-
-Names beginning with "flux::" are reserved for internal use.
-
-RETURN VALUE
-------------
-
-`flux_aux_get()` returns data on success, or NULL on failure, with errno set.
-
-`flux_aux_set()` returns 0 on success, or -1 on failure, with errno set.
-
-
-ERRORS
-------
-
-EINVAL::
-Some arguments were invalid.
-
-ENOMEM::
-Out of memory.
-
-ENOENT::
-`flux_aux_get()` could not find an entry for _key_.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_open(3)
diff --git a/doc/man3/flux_aux_set.rst b/doc/man3/flux_aux_set.rst
new file mode 100644
index 000000000000..d56625eea9bb
--- /dev/null
+++ b/doc/man3/flux_aux_set.rst
@@ -0,0 +1,77 @@
+===============
+flux_aux_set(3)
+===============
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ typedef void (*flux_free_f)(void *arg);
+
+ void *flux_aux_get (flux_t *h, const char *name);
+
+ int flux_aux_set (flux_t *h,
+ const char *name,
+ void *aux,
+ flux_free_f destroy);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_aux_set` attaches application-specific data
+to the parent object :var:`h`. It stores data :var:`aux` by key :var:`name`,
+with optional destructor :var:`destroy`. The destructor, if non-NULL,
+is called when the parent object is destroyed, or when
+:var:`key` is overwritten by a new value. If :var:`aux` is NULL,
+the destructor for a previous value, if any is called,
+but no new value is stored. If :var:`name` is NULL,
+:var:`aux` is stored anonymously.
+
+:func:`flux_aux_get` retrieves application-specific data
+by :var:`name`. If the data was stored anonymously, it
+cannot be retrieved. Note that :func:`flux_aux_get` does not scale to a
+large number of items, and flux module handles may persist for a long
+time.
+
+Names beginning with "flux::" are reserved for internal use.
+
+
+RETURN VALUE
+============
+
+:func:`flux_aux_get` returns data on success, or NULL on failure,
+with :var:`errno` set.
+
+:func:`flux_aux_set` returns 0 on success, or -1 on failure, with errno set.
+
+
+ERRORS
+======
+
+EINVAL
+ Some arguments were invalid.
+
+ENOMEM
+ Out of memory.
+
+ENOENT
+ :func:`flux_aux_get` could not find an entry for *key*.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_open`
diff --git a/doc/man3/flux_child_watcher_create.adoc b/doc/man3/flux_child_watcher_create.adoc
deleted file mode 100644
index 50dd0f193d0d..000000000000
--- a/doc/man3/flux_child_watcher_create.adoc
+++ /dev/null
@@ -1,85 +0,0 @@
-flux_child_watcher_create(3)
-============================
-:doctype: manpage
-
-
-NAME
-----
-flux_child_watcher_create, flux_child_watcher_get_rpid, flux_child_watcher_get_rstatus - create child watcher
-
-
-SYNOPSIS
---------
- #include
-
- typedef void (*flux_watcher_f)(flux_reactor_t *r,
- flux_watcher_t *w,
- int revents, void *arg);
-
- flux_watcher_t *flux_child_watcher_create (flux_reactor_t *r,
- int pid, bool trace,
- flux_watcher_f cb, void *arg);
-
- int flux_child_watcher_get_rpid (flux_watcher_t *w);
-
- int flux_child_watcher_get_rstatus (flux_watcher_t *w);
-
-
-DESCRIPTION
------------
-
-`flux_child_watcher_create()` creates a reactor watcher that
-monitors state transitions of child processes. If _trace_ is false,
-only child termination will trigger an event; otherwise, stop and start
-events may be generated.
-
-The callback _revents_ argument should be ignored.
-
-The process id that had a transition may be obtained by calling
-`flux_child_watcher_get_rpid()`.
-
-The status value returned by waitpid(2) may be obtained by calling
-`flux_child_watcher_get_rstatus()`.
-
-Only a Flux reactor created with the FLUX_REACTOR_SIGCHLD flag can
-be used with child watchers, as the reactor must register a SIGCHLD
-signal watcher before any processes are spawned. Only one reactor instance
-per program may be created with this capability.
-
-
-RETURN VALUE
-------------
-
-flux_child_watcher_create() returns a flux_watcher_t object on success.
-On error, NULL is returned, and errno is set appropriately.
-
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-EINVAL::
-Reactor was not created with FLUX_REACTOR_SIGCHLD.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_watcher_start(3), flux_reactor_start(3)
-
-http://software.schmorp.de/pkg/libev.html[libev home page]
diff --git a/doc/man3/flux_child_watcher_create.rst b/doc/man3/flux_child_watcher_create.rst
new file mode 100644
index 000000000000..a1d2d8478508
--- /dev/null
+++ b/doc/man3/flux_child_watcher_create.rst
@@ -0,0 +1,81 @@
+============================
+flux_child_watcher_create(3)
+============================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ typedef void (*flux_watcher_f)(flux_reactor_t *r,
+ flux_watcher_t *w,
+ int revents,
+ void *arg);
+
+ flux_watcher_t *flux_child_watcher_create (flux_reactor_t *r,
+ int pid,
+ bool trace,
+ flux_watcher_f cb,
+ void *arg);
+
+ int flux_child_watcher_get_rpid (flux_watcher_t *w);
+
+ int flux_child_watcher_get_rstatus (flux_watcher_t *w);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_child_watcher_create` creates a reactor watcher that
+monitors state transitions of child processes. If :var:`trace` is false,
+only child termination will trigger an event; otherwise, stop and start
+events may be generated.
+
+The callback :var:`revents` argument should be ignored.
+
+The process id that had a transition may be obtained by calling
+:func:`flux_child_watcher_get_rpid`.
+
+The status value returned by :linux:man2:`waitpid` may be obtained by calling
+:func:`flux_child_watcher_get_rstatus`.
+
+Only a Flux reactor created with the FLUX_REACTOR_SIGCHLD flag can
+be used with child watchers, as the reactor must register a SIGCHLD
+signal watcher before any processes are spawned. Only one reactor instance
+per program may be created with this capability.
+
+
+RETURN VALUE
+============
+
+:func:`flux_child_watcher_create` returns a :type:`flux_watcher_t` object on
+success. On error, NULL is returned, and :var:`errno` is set appropriately.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+EINVAL
+ Reactor was not created with FLUX_REACTOR_SIGCHLD.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+libev: http://software.schmorp.de/pkg/libev.html
+
+
+SEE ALSO
+========
+
+:man3:`flux_watcher_start`, :man3:`flux_reactor_run`
diff --git a/doc/man3/flux_comms_error_set.rst b/doc/man3/flux_comms_error_set.rst
new file mode 100644
index 000000000000..5bbe343fba1d
--- /dev/null
+++ b/doc/man3/flux_comms_error_set.rst
@@ -0,0 +1,52 @@
+=======================
+flux_comms_error_set(3)
+=======================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ typedef int (*flux_comms_error_f)(flux_t *h, void *arg);
+
+ void flux_comms_error_set (flux_t *h,
+ flux_comms_error_f fun,
+ void *arg);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_comms_error_set` configures an optional callback :var:`fun` to
+be called internally by ``libflux_core`` if an error occurs when sending
+or receiving messages on the handle :var:`h`.
+
+:var:`arg` is an optional argument passed through to the callback function.
+
+The callback may assume that :var:`errno` is valid. A typical callback in an
+application might log the error and then exit.
+
+If a comms error function is not registered, or if the function returns -1,
+error handling proceeds as normal. Be aware that further access attempts
+to :var:`h` are likely to fail and the callback may be invoked again.
+
+In advanced use cases, the callback may resolve the error and return 0,
+in which case the errant low level message send or receive call is retried.
+This mode should be considered experimental at this time.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_open`
diff --git a/doc/man3/flux_content_load.adoc b/doc/man3/flux_content_load.adoc
deleted file mode 100644
index b5c98bf81858..000000000000
--- a/doc/man3/flux_content_load.adoc
+++ /dev/null
@@ -1,137 +0,0 @@
-flux_content_load(3)
-====================
-:doctype: manpage
-
-
-NAME
-----
-flux_content_load, flux_content_load_get, flux_content_store, flux_content_store_get - load/store content
-
-
-SYNOPSIS
---------
- #include
-
- flux_future_t *flux_content_load (flux_t *h,
- const char *blobref,
- int flags);
-
- int flux_content_load_get (flux_future_t *f,
- const void **buf,
- size_t *len);
-
-
- flux_future_t *flux_content_store (flux_t *h,
- const void *buf,
- size_t len,
- int flags);
-
- int flux_content_store_get (flux_future_t *f,
- const char **ref);
-
-
-DESCRIPTION
------------
-
-The Flux content service is an append-only, immutable, content addressed
-data storage service unique to each Flux instance, described in RFC 10.
-All functions described below are idempotent.
-
-`flux_content_load()` sends a request to the content service
-to load a data blob by _blobref_, a hash digest whose format
-is described in RFC 10. A `flux_future_t` object which encapsulates the
-remote procedure call state is returned. _flags_ is a mask that may
-include the values described below.
-
-`flux_request_load_get()` completes a load operation, blocking on
-response(s) if needed, parsing the result, and returning the requested
-blob in _buf_ and its length in _len_. _buf_ is valid until
-`flux_future_destroy()` is called.
-
-`flux_content_store()` sends a request to the content service
-to store a data blob _buf_ of length _len_. A `flux_future_t`
-object which encapsulates the remote procedure call state is returned.
-_flags_ is a mask that may include the values described below.
-
-`flux_content_store_get()` completes a store operation, blocking on
-response(s) if needed, and returning a blobref that can be used to
-retrieve the stored blob. The blobref string is valid until
-`flux_future_destroy()` is called.
-
-These functions may be used asynchronously.
-See `flux_future_then(3)` for details.
-
-
-FLAGS
------
-
-The following are valid bits in a _flags_ mask passed as an argument
-to `flux_content_load()` or `flux_content_store()`.
-
-CONTENT_FLAG_CACHE_BYPASS::
-Send the request directly to the backing store (default sqlite),
-bypassing the cache.
-
-CONTENT_FLAG_UPSTREAM::
-Direct the request to the next broker upstream on the TBON rather
-than to the local broker.
-
-
-RETURN VALUE
-------------
-
-`flux_content_load()` and `flux_content_store()` return a
-`flux_future_t` on success, or NULL on failure with errno set appropriately.
-
-`flux_content_load_get()` and `flux_content_store_get()`
-return 0 on success, or -1 on failure with errno set appropriately.
-
-
-ERRORS
-------
-
-EINVAL::
-One of the arguments was invalid.
-
-ENOMEM::
-Out of memory.
-
-ENOENT::
-An unknown blob was requested.
-
-EPROTO::
-A request was malformed.
-
-EFBIG::
-A blob larger than the configured maximum blob size
-could not be stored. See flux-broker-attributes(7).
-
-ENOSYS::
-The CONTENT_FLAG_CACHE_BYPASS flag was set in a request, but no
-backing store module is loaded.
-
-EHOSTUNREACH::
-The CONTENT_FLAG_UPSTREAM flag was set in a request received by
-the rank 0 broker.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_rpc(3), flux_future_get(3)
-
-https://github.com/flux-framework/rfc/blob/master/spec_10.adoc[RFC 10: Content Storage Service]
diff --git a/doc/man3/flux_core_version.adoc b/doc/man3/flux_core_version.adoc
deleted file mode 100644
index b07bfd00611a..000000000000
--- a/doc/man3/flux_core_version.adoc
+++ /dev/null
@@ -1,94 +0,0 @@
-flux_core_version(3)
-====================
-:doctype: manpage
-
-
-NAME
-----
-flux_core_version, flux_core_version_string - get flux-core version
-
-
-SYNOPSIS
---------
- #include
-
- int flux_core_version (int *major, int *minor, int *patch);
-
- const char *flux_core_version_string (void);
-
-
-DESCRIPTION
------------
-
-flux-core defines several macros and functions to let API users determine
-the version they are working with. A version has three components
-(_major_, _minor_, _patch_), accessible with the following macros:
-
-FLUX_CORE_VERSION_MAJOR::
-(integer) incremented when there are incompatible API changes
-
-FLUX_CORE_VERSION_MINOR::
-(integer) incremented when functionality is added in a backwards-compatible
-manner
-
-FLUX_CORE_VERSION_PATCH::
-(integer) incremented when bug fixes are added in a backwards-compatible manner
-
-These definitions conform to the _semantic versioning_ standard (see below).
-In addition, the following convenience macros are available:
-
-FLUX_CORE_VERSION_HEX::
-(hex) the three versions combined into a three-byte integer value,
-useful for comparing versions with '<', '=', and '>' operators.
-
-FLUX_CORE_VERSION_STRING::
-(string) the three versions above separated by periods, with optional
-`git-describe(1)` suffix preceded by a hyphen, if the version is a
-development snapshot.
-
-Note that major version zero (0.y.z) is for initial development.
-Under version zero, the public API should not be considered stable.
-
-Functions are also available to access the same values. While the header
-macros tell what version of flux-core your program was compiled against,
-the functions tell what version your program is dynamically linked with.
-
-`flux_core_version()` sets _major_, _minor_, and _patch_ to the values of
-the macros above. If any parameters are NULL, no assignment is attempted.
-
-`flux_core_version_string()` returns the string value.
-
-
-RETURN VALUE
-------------
-
-`flux_core_version ()` returns the hex version.
-
-`flux_core_version_string ()` returns the version string
-
-
-
-ERRORS
-------
-
-These functions cannot fail.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-semver.org[Semantic Versioning 2.0.0]
diff --git a/doc/man3/flux_core_version.rst b/doc/man3/flux_core_version.rst
new file mode 100644
index 000000000000..39000334f3bf
--- /dev/null
+++ b/doc/man3/flux_core_version.rst
@@ -0,0 +1,82 @@
+====================
+flux_core_version(3)
+====================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ int flux_core_version (int *major, int *minor, int *patch);
+
+ const char *flux_core_version_string (void);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+flux-core defines several macros and functions to let API users determine
+the version they are working with. A version has three components
+(*major*, *minor*, *patch*), accessible with the following macros:
+
+FLUX_CORE_VERSION_MAJOR
+ (integer) incremented when there are incompatible API changes
+
+FLUX_CORE_VERSION_MINOR
+ (integer) incremented when functionality is added in a backwards-compatible
+ manner
+
+FLUX_CORE_VERSION_PATCH
+ (integer) incremented when bug fixes are added in a backwards-compatible manner
+
+These definitions conform to the *semantic versioning* standard (see below).
+In addition, the following convenience macros are available:
+
+FLUX_CORE_VERSION_HEX
+ (hex) the three versions combined into a three-byte integer value,
+ useful for comparing versions with *<*, *=*, and *>* operators.
+
+FLUX_CORE_VERSION_STRING
+ (string) the three versions above separated by periods, with optional
+ :linux:man1:`git-describe` suffix preceded by a hyphen, if the version is a
+ development snapshot.
+
+Note that major version zero (0.y.z) is for initial development.
+Under version zero, the public API should not be considered stable.
+
+Functions are also available to access the same values. While the header
+macros tell what version of flux-core your program was compiled against,
+the functions tell what version your program is dynamically linked with.
+
+:func:`flux_core_version` sets :var:`major`, :var:`minor`, and :var:`patch`
+to the values of the macros above. If any parameters are NULL, no assignment
+is attempted.
+
+:func:`flux_core_version_string` returns the string value.
+
+
+RETURN VALUE
+============
+
+:func:`flux_core_version` returns the hex version.
+
+:func:`flux_core_version_string` returns the version string
+
+
+ERRORS
+======
+
+These functions cannot fail.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+Semantic Versioning 2.0.0: http://semver.org
diff --git a/doc/man3/flux_event_decode.adoc b/doc/man3/flux_event_decode.adoc
deleted file mode 100644
index 9fda00cf0875..000000000000
--- a/doc/man3/flux_event_decode.adoc
+++ /dev/null
@@ -1,121 +0,0 @@
-flux_event_decode(3)
-====================
-:doctype: manpage
-
-
-NAME
-----
-flux_event_decode, flux_event_decode_raw, flux_event_unpack, flux_event_encode, flux_event_encode_raw, flux_event_pack - encode/decode a Flux event message
-
-
-SYNOPSIS
---------
- #include
-
- int flux_event_decode (const flux_msg_t *msg,
- const char **topic,
- const char **s);
-
- int flux_event_decode_raw (const flux_msg_t *msg,
- const char **topic,
- const void **data, int *len);
-
- int flux_event_unpack (const flux_msg_t *msg,
- const char **topic,
- const char *fmt, ...);
-
- flux_msg_t *flux_event_encode (const char *topic,
- const char *s);
-
- flux_msg_t *flux_event_encode_raw (const char *topic,
- const void *data, int len);
-
- flux_msg_t *flux_event_pack (const char *topic,
- const char *fmt, ...);
-
-
-DESCRIPTION
------------
-
-`flux_event_decode()` decodes a Flux event message _msg_.
-
-_topic_, if non-NULL, will be set to the message's topic string. The storage
-for this string belongs to _msg_ and should not be freed.
-
-_s_, if non-NULL, will be set to the message's NULL-terminated string payload.
-If no payload exists, it is set to NULL. The storage for this string belongs
-to _msg_ and should not be freed.
-
-`flux_event_decode_raw()` decodes an event message with a raw payload,
-setting _data_ and _len_ to the payload data and length. The storage for
-the raw payload belongs to _msg_ and should not be freed.
-
-`flux_event_unpack()` decodes a Flux event message with a JSON payload as
-above, parsing the payload using variable arguments with a format string
-in the style of jansson's `json_unpack()` (used internally). Decoding fails
-if the message doesn't have a JSON payload.
-
-`flux_event_encode()` encodes a Flux event message with topic string _topic_
-and optional NULL-terminated string payload _s_. The newly constructed
-message that is returned must be destroyed with `flux_msg_destroy()`.
-
-`flux_event_encode_raw()` encodes a Flux event message with topic
-string _topic_. If _data_ is non-NULL, its contents will be used as
-the message payload, and the payload type set to raw.
-
-`flux_event_pack()` encodes a Flux event message with a JSON payload as
-above, encoding the payload using variable arguments with a format string
-in the style of jansson's `json_pack()` (used internally). Decoding fails
-if the message doesn't have a JSON payload.
-
-Events propagated to all subscribers. Events will not be received
-without a matching subscription established using `flux_event_subscribe()`.
-
-include::JSON_PACK.adoc[]
-
-
-include::JSON_UNPACK.adoc[]
-
-
-RETURN VALUE
-------------
-
-Decoding functions return 0 on success. On error, -1 is returned, and
-errno is set appropriately.
-
-Encoding functions return a message on success. On error, NULL is returned,
-and errno is set appropriately.
-
-
-ERRORS
-------
-
-EINVAL::
-The _msg_ argument was NULL or there was a problem encoding.
-
-ENOMEM::
-Memory was unavailable.
-
-EPROTO::
-Message decoding failed, such as due to incorrect message type,
-missing topic string, etc..
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_event_subscribe(3)
diff --git a/doc/man3/flux_event_decode.rst b/doc/man3/flux_event_decode.rst
new file mode 100644
index 000000000000..591ce35de57c
--- /dev/null
+++ b/doc/man3/flux_event_decode.rst
@@ -0,0 +1,122 @@
+====================
+flux_event_decode(3)
+====================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ int flux_event_decode (const flux_msg_t *msg,
+ const char **topic,
+ const char **s);
+
+ int flux_event_decode_raw (const flux_msg_t *msg,
+ const char **topic,
+ const void **data,
+ size_t *len);
+
+ int flux_event_unpack (const flux_msg_t *msg,
+ const char **topic,
+ const char *fmt,
+ ...);
+
+ flux_msg_t *flux_event_encode (const char *topic, const char *s);
+
+ flux_msg_t *flux_event_encode_raw (const char *topic,
+ const void *data,
+ size_t len);
+
+ flux_msg_t *flux_event_pack (const char *topic,
+ const char *fmt,
+ ...);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_event_decode` decodes a Flux event message :var:`msg`.
+
+:var:`topic`, if non-NULL, will be set to the message's topic string. The
+storage for this string belongs to :var:`msg` and should not be freed.
+
+:var:`s`, if non-NULL, will be set to the message's NULL-terminated string
+payload. If no payload exists, it is set to NULL. The storage for this string
+belongs to :var:`msg` and should not be freed.
+
+:func:`flux_event_decode_raw` decodes an event message with a raw payload,
+setting :var:`data` and :var:`len` to the payload data and length. The storage
+for the raw payload belongs to :var:`msg` and should not be freed.
+
+:func:`flux_event_unpack` decodes a Flux event message with a JSON payload as
+above, parsing the payload using variable arguments with a format string
+in the style of jansson's :func:`json_unpack` (used internally). Decoding fails
+if the message doesn't have a JSON payload.
+
+:func:`flux_event_encode` encodes a Flux event message with topic string
+:var:`topic` and optional NULL-terminated string payload :var:`s`. The newly
+constructed message that is returned must be destroyed with
+:func:`flux_msg_destroy()`.
+
+:func:`flux_event_encode_raw` encodes a Flux event message with topic
+string :var:`topic`. If :var:`data` is non-NULL, its contents will be used as
+the message payload, and the payload type set to raw.
+
+:func:`flux_event_pack` encodes a Flux event message with a JSON payload as
+above, encoding the payload using variable arguments with a format string
+in the style of jansson's :func:`json_pack` (used internally). Decoding fails
+if the message doesn't have a JSON payload.
+
+Events propagated to all subscribers. Events will not be received
+without a matching subscription established using :func:`flux_event_subscribe`.
+
+ENCODING JSON PAYLOADS
+======================
+
+.. include:: common/json_pack.rst
+
+DECODING JSON PAYLOADS
+======================
+
+.. include:: common/json_unpack.rst
+
+
+RETURN VALUE
+============
+
+Decoding functions return 0 on success. On error, -1 is returned, and
+:var:`errno` is set appropriately.
+
+Encoding functions return a message on success. On error, NULL is returned,
+and :var:`errno` is set appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ The :var:`msg` argument was NULL or there was a problem encoding.
+
+ENOMEM
+ Memory was unavailable.
+
+EPROTO
+ Message decoding failed, such as due to incorrect message type,
+ missing topic string, etc.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_event_subscribe`
diff --git a/doc/man3/flux_event_publish.adoc b/doc/man3/flux_event_publish.adoc
deleted file mode 100644
index 1555b5bfc115..000000000000
--- a/doc/man3/flux_event_publish.adoc
+++ /dev/null
@@ -1,118 +0,0 @@
-flux_event_publish(3)
-=====================
-:doctype: manpage
-
-
-NAME
-----
-flux_event_publish, flux_event_publish_pack, flux_event_publish_raw, flux_event_publish_get_seq - publish events
-
-
-SYNOPSIS
---------
- #include
-
- flux_future_t *flux_event_publish (flux_t *h,
- const char *topic, int flags,
- const char *s);
-
- flux_future_t *flux_event_publish_pack (flux_t *h,
- const char *topic, int flags,
- const char *fmt, ...);
-
- flux_future_t *flux_event_publish_raw (flux_t *h,
- const char *topic, int flags,
- const void *data, int len);
-
- int flux_event_publish_get_seq (flux_future_t *f, int *seq);
-
-DESCRIPTION
------------
-
-`flux_event_publish()` sends an event message with topic string _topic_,
-_flags_ as described below, and optional payload _s_, a NULL-terminated
-string, or NULL indicating no payload. The returned future is
-fulfilled once the event is accepted by the broker and assigned a
-global sequence number.
-
-`flux_event_publish_pack()` is similar, except the JSON payload
-is constructed using `json_pack()` style arguments (see below).
-
-`flux_event_publish_raw()` is similar, except the payload is raw _data_
-of length _len_.
-
-`flux_event_publish_get_seq()` may be used to retrieve the sequence
-number assigned to the message once the future is fulfilled.
-
-
-CONFIRMATION SEMANTICS
-----------------------
-
-All Flux events are "open loop" in the sense that publishers get no
-confirmation that subscribers have received a message. However,
-the above functions do confirm, upon fulfillment of the returned future,
-that the published event has been received by the broker and assigned
-a global sequence number.
-
-Gaps in the sequence trigger the logging of errors currently, and in
-the future will trigger recovery of lost events, so these confirmations
-do indicate that Flux's best effort at event propagation is under way.
-
-If this level of confirmation is not required, one may encode
-an event message directly using `flux_event_encode(3)` and related
-functions and send it directly with `flux_send(3)`.
-
-
-FLAGS
------
-
-The _flags_ argument in the above functions must be zero, or the
-logical OR of the following values:
-
-FLUX_MSGFLAG_PRIVATE::
-Indicates that the event should only be visible to the instance owner
-and the sender.
-
-
-
-include::JSON_PACK.adoc[]
-
-
-RETURN VALUE
-------------
-
-These functions return a future on success. On error, NULL is returned,
-and errno is set appropriately.
-
-
-ERRORS
-------
-
-EINVAL::
-Some arguments were invalid.
-
-ENOMEM::
-Out of memory.
-
-EPROTO::
-A protocol error was encountered.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-flux_event_decode(3), flux_event_subscribe(3)
diff --git a/doc/man3/flux_event_publish.rst b/doc/man3/flux_event_publish.rst
new file mode 100644
index 000000000000..239f81cd1be9
--- /dev/null
+++ b/doc/man3/flux_event_publish.rst
@@ -0,0 +1,117 @@
+=====================
+flux_event_publish(3)
+=====================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_future_t *flux_event_publish (flux_t *h,
+ const char *topic,
+ int flags,
+ const char *s);
+
+ flux_future_t *flux_event_publish_pack (flux_t *h,
+ const char *topic,
+ int flags,
+ const char *fmt,
+ ...);
+
+ flux_future_t *flux_event_publish_raw (flux_t *h,
+ const char *topic,
+ int flags,
+ const void *data,
+ size_t len);
+
+ int flux_event_publish_get_seq (flux_future_t *f, int *seq);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_event_publish` sends an event message with topic string
+:var:`topic`, :var:`flags` as described below, and optional payload :var:`s`,
+a NULL-terminated string, or NULL indicating no payload. The returned future
+is fulfilled once the event is accepted by the broker and assigned a
+global sequence number.
+
+:func:`flux_event_publish_pack` is similar, except the JSON payload
+is constructed using :func:`json_pack` style arguments (see below).
+
+:func:`flux_event_publish_raw` is similar, except the payload is raw
+:var:`data` of length :var:`len`.
+
+:func:`flux_event_publish_get_seq` may be used to retrieve the sequence
+number assigned to the message once the future is fulfilled.
+
+
+CONFIRMATION SEMANTICS
+======================
+
+All Flux events are "open loop" in the sense that publishers get no
+confirmation that subscribers have received a message. However,
+the above functions do confirm, upon fulfillment of the returned future,
+that the published event has been received by the broker and assigned
+a global sequence number.
+
+Gaps in the sequence trigger the logging of errors currently, and in
+the future will trigger recovery of lost events, so these confirmations
+do indicate that Flux's best effort at event propagation is under way.
+
+If this level of confirmation is not required, one may encode
+an event message directly using :man3:`flux_event_encode` and related
+functions and send it directly with :man3:`flux_send`.
+
+
+FLAGS
+=====
+
+The :var:`flags` argument in the above functions must be zero, or the
+logical OR of the following values:
+
+FLUX_MSGFLAG_PRIVATE
+ Indicates that the event should only be visible to the instance owner
+ and the sender.
+
+ENCODING JSON PAYLOADS
+======================
+
+.. include:: common/json_pack.rst
+
+
+RETURN VALUE
+============
+
+These functions return a future on success. On error, NULL is returned,
+and errno is set appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ Some arguments were invalid.
+
+ENOMEM
+ Out of memory.
+
+EPROTO
+ A protocol error was encountered.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_event_decode`, :man3:`flux_event_subscribe`
diff --git a/doc/man3/flux_event_subscribe.adoc b/doc/man3/flux_event_subscribe.adoc
deleted file mode 100644
index 545d01d22b95..000000000000
--- a/doc/man3/flux_event_subscribe.adoc
+++ /dev/null
@@ -1,87 +0,0 @@
-flux_event_subscribe(3)
-=======================
-:doctype: manpage
-
-
-NAME
-----
-flux_event_subscribe, flux_event_unsubscribe - manage subscriptions
-
-
-SYNOPSIS
---------
-#include
-
-int flux_event_subscribe (flux_t *h, const char *topic);
-
-int flux_event_unsubscribe (flux_t *h, const char *topic);
-
-
-DESCRIPTION
------------
-
-Flux events are broadcast across the session, but are only delivered
-to handles that subscribe to them by topic. Topic strings consist of
-one or more words separated by periods, interpreted as a hierarchical
-name space.
-
-`flux_event_subscribe()` requests that event messages matching _topic_
-be delivered via `flux_recv(3)`. A match consists of a string comparison
-of the event topic and the subscription topic, up to the length of the
-subscription topic. Thus "foo." matches events with topics "foo.bar"
-and "foo.baz", and "" matches all events. This matching algorithm
-is inherited from ZeroMQ. Globs or regular expressions are not allowed
-in subscriptions, and the period delimiter is included in the comparison.
-
-`flux_event_unsubscribe()` unsubscribes to a topic. The _topic_
-argument must exactly match that provided to `flux_event_subscribe()`.
-
-Duplicate subscriptions are allowed in the subscription list but
-will not result in multiple deliveries of a given message. Each
-duplicate subscription requires a separate unsubscribe.
-
-It is not necessary to remove subscriptions with `flux_event_unsubscribe()`
-prior to calling `flux_close(3)`.
-
-RETURN VALUE
-------------
-
-These functions return 0 on success. On error, -1 is returned,
-and errno is set appropriately.
-
-
-ERRORS
-------
-
-EINVAL::
-Some arguments were invalid.
-
-ENOMEM::
-Out of memory.
-
-
-EXAMPLES
---------
-
-This example opens the Flux broker, subscribes to heartbeat messages,
-displays one, then quits.
-
-....
-include::tevent.c[]
-....
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
diff --git a/doc/man3/flux_event_subscribe.rst b/doc/man3/flux_event_subscribe.rst
new file mode 100644
index 000000000000..8ef2f92a2558
--- /dev/null
+++ b/doc/man3/flux_event_subscribe.rst
@@ -0,0 +1,77 @@
+=======================
+flux_event_subscribe(3)
+=======================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ int flux_event_subscribe (flux_t *h, const char *topic);
+
+ int flux_event_unsubscribe (flux_t *h, const char *topic);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+Flux events are broadcast across the session, but are only delivered
+to handles that subscribe to them by topic. Topic strings consist of
+one or more words separated by periods, interpreted as a hierarchical
+name space.
+
+:func:`flux_event_subscribe` requests that event messages matching :var:`topic`
+be delivered via :man3:`flux_recv`. A match consists of a string comparison
+of the event topic and the subscription topic, up to the length of the
+subscription topic. Thus "foo." matches events with topics "foo.bar"
+and "foo.baz", and "" matches all events. This matching algorithm
+is inherited from ZeroMQ. Globs or regular expressions are not allowed
+in subscriptions, and the period delimiter is included in the comparison.
+
+:func:`flux_event_unsubscribe` unsubscribes to a topic. The :var:`topic`
+argument must exactly match that provided to :func:`flux_event_subscribe`.
+
+Duplicate subscriptions are allowed in the subscription list but
+will not result in multiple deliveries of a given message. Each
+duplicate subscription requires a separate unsubscribe.
+
+It is not necessary to remove subscriptions with :func:`flux_event_unsubscribe`
+prior to calling :man3:`flux_close`.
+
+
+RETURN VALUE
+============
+
+These functions return 0 on success. On error, -1 is returned,
+and errno is set appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ Some arguments were invalid.
+
+ENOMEM
+ Out of memory.
+
+
+EXAMPLES
+========
+
+This example opens the Flux broker, subscribes to heartbeat messages,
+displays one, then quits.
+
+.. literalinclude:: example/event.c
+ :language: c
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
diff --git a/doc/man3/flux_fatal_set.adoc b/doc/man3/flux_fatal_set.adoc
deleted file mode 100644
index 5e408623019a..000000000000
--- a/doc/man3/flux_fatal_set.adoc
+++ /dev/null
@@ -1,67 +0,0 @@
-flux_fatal_set(3)
-=================
-:doctype: manpage
-
-
-NAME
-----
-flux_fatal_set, flux_fatal_error, FLUX_FATAL - register/call fatal error
-function
-
-
-SYNOPSIS
---------
-#include
-
-typedef void (*flux_fatal_f)(const char *msg, void *arg);
-
-void flux_fatal_set (flux_t *h, flux_fatal_f fun, void *arg);
-
-void flux_fatal_error (flux_t *h, const char *fun, const char *msg);
-
-FLUX_FATAL (flux_t *h);
-
-
-DESCRIPTION
------------
-
-`flux_fatal_set()` configures an optional fatal error function _fun_ to
-be called internally by `libflux_core` if an error occurs that is fatal
-to the handle _h_. A fatal error is any error that renders the handle
-unusable. The function may log _msg_, terminate the program,
-or take other action appropriate to the application.
-
-If a fatal error function is not registered, or if the fatal error
-function returns, error handling proceeds as normal.
-
-The fatal error function will only be called once, for the first
-fatal error encountered.
-
-_arg_ is an optional argument passed through to the fatal error function.
-
-`FLUX_FATAL()` is a macro that calls
-....
-flux_fatal_error (h, __FUNCTION__, strerror (errno))
-....
-which translates to a fatal error function called with _msg_ set to
-"function name: error string".
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_open(3)
diff --git a/doc/man3/flux_fd_watcher_create.adoc b/doc/man3/flux_fd_watcher_create.adoc
deleted file mode 100644
index 63839a12795e..000000000000
--- a/doc/man3/flux_fd_watcher_create.adoc
+++ /dev/null
@@ -1,91 +0,0 @@
-flux_fd_watcher_create(3)
-=========================
-:doctype: manpage
-
-
-NAME
-----
-flux_fd_watcher_create, flux_fd_watcher_get_fd - create file descriptor watcher
-
-
-SYNOPSIS
---------
- #include
-
- typedef void (*flux_watcher_f)(flux_reactor_t *r,
- flux_watcher_t *w,
- int revents, void *arg);
-
- flux_watcher_t *flux_fd_watcher_create (flux_reactor_t *r,
- int fd, int events,
- flux_watcher_f callback,
- void *arg);
-
- int flux_fd_watcher_get_fd (flux_watcher_t *w);
-
-
-DESCRIPTION
------------
-
-`flux_fd_watcher_create()` creates a flux_watcher_t object which can be used
-to monitor for events on a file descriptor _fd_. When events occur,
-the user-supplied _callback_ is invoked.
-
-The _events_ and _revents_ arguments are a bitmask containing a logical
-``or'' of the following bits. If a bit is set in _events_, it indicates
-interest in this type of event. If a bit is set in _revents_, it
-indicates that this event has occurred.
-
-FLUX_POLLIN::
-The file descriptor is ready for reading.
-
-FLUX_POLLOUT::
-The file descriptor is ready for writing.
-
-FLUX_POLLERR::
-The file descriptor has encountered an error.
-This bit is ignored if it is set in the create _events_ argument.
-
-Events are processed in a level-triggered manner. That is, the callback
-will continue to be invoked as long as the event has not been
-fully consumed or cleared, and the watcher has not been stopped.
-
-`flux_fd_watcher_get_fd()` is used to obtain the file descriptor from
-within the flux_watcher_f callback.
-
-
-RETURN VALUE
-------------
-
-`flux_fd_watcher_create()` returns a flux_watcher_t object on success.
-On error, NULL is returned, and errno is set appropriately.
-
-`flux_fd_watcher_get_fd()` returns the file descriptor associated with
-the watcher.
-
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_watcher_start(3), flux_reactor_start(3).
diff --git a/doc/man3/flux_fd_watcher_create.rst b/doc/man3/flux_fd_watcher_create.rst
new file mode 100644
index 000000000000..09c98db1048a
--- /dev/null
+++ b/doc/man3/flux_fd_watcher_create.rst
@@ -0,0 +1,85 @@
+=========================
+flux_fd_watcher_create(3)
+=========================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ typedef void (*flux_watcher_f)(flux_reactor_t *r,
+ flux_watcher_t *w,
+ int revents,
+ void *arg);
+
+ flux_watcher_t *flux_fd_watcher_create (flux_reactor_t *r,
+ int fd,
+ int events,
+ flux_watcher_f callback,
+ void *arg);
+
+ int flux_fd_watcher_get_fd (flux_watcher_t *w);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_fd_watcher_create()` creates a :type:`flux_watcher_t` object which
+can be used to monitor for events on a file descriptor :var:`fd`. When events
+occur, the user-supplied :var:`callback` is invoked.
+
+The :var:`events` and :var:`revents` arguments are a bitmask containing a
+logical OR of the following bits. If a bit is set in :var:`events`, it
+indicates interest in this type of event. If a bit is set in :var:`revents`, it
+indicates that this event has occurred.
+
+FLUX_POLLIN
+ The file descriptor is ready for reading.
+
+FLUX_POLLOUT
+ The file descriptor is ready for writing.
+
+FLUX_POLLERR
+ The file descriptor has encountered an error.
+ This bit is ignored if it is set in the create *events* argument.
+
+Events are processed in a level-triggered manner. That is, the callback
+will continue to be invoked as long as the event has not been
+fully consumed or cleared, and the watcher has not been stopped.
+
+:func:`flux_fd_watcher_get_fd` is used to obtain the file descriptor from
+within the :type:`flux_watcher_f callback`.
+
+
+RETURN VALUE
+============
+
+:func:`flux_fd_watcher_create` returns a :type:`flux_watcher_t` object on
+success. On error, NULL is returned, and :var:`errno` is set appropriately.
+
+:func:`flux_fd_watcher_get_fd` returns the file descriptor associated with
+the watcher.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_watcher_start`, :man3:`flux_reactor_run`
diff --git a/doc/man3/flux_flags_set.adoc b/doc/man3/flux_flags_set.adoc
deleted file mode 100644
index 07def1a8979f..000000000000
--- a/doc/man3/flux_flags_set.adoc
+++ /dev/null
@@ -1,66 +0,0 @@
-flux_flags_set(3)
-=================
-:doctype: manpage
-
-
-NAME
-----
-flux_flags_set, flux_flags_unset, flux_flags_get - manipulate Flux handle flags
-
-
-SYNOPSIS
---------
-#include
-
-void flux_flags_set (flux_t *h, int flags);
-
-void flux_flags_unset (flux_t *h, int flags);
-
-int flux_flags_get (flux_t *h);
-
-
-DESCRIPTION
------------
-
-`flux_flags_set()` sets new open _flags_ in handle _h_. The resulting
-handle flags will be a logical or of the old flags and the new.
-
-`flux_flags_unset()` clears open _flags_ in handle _h_. The resulting
-handle flags will be a logical and of the old flags and the inverse of the new.
-
-`flux_flags_get()` can be used to retrieve the current open flags from
-handle _h_.
-
-The valid flags are described in `flux_open(3)`.
-
-
-RETURN VALUE
-------------
-
-`flux_flags_get()` returns the current flags.
-
-
-ERRORS
-------
-
-These functions never fail.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_open(3)
diff --git a/doc/man3/flux_flags_set.rst b/doc/man3/flux_flags_set.rst
new file mode 100644
index 000000000000..880335c34796
--- /dev/null
+++ b/doc/man3/flux_flags_set.rst
@@ -0,0 +1,59 @@
+=================
+flux_flags_set(3)
+=================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ void flux_flags_set (flux_t *h, int flags);
+
+ void flux_flags_unset (flux_t *h, int flags);
+
+ int flux_flags_get (flux_t *h);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_flags_set` sets new open :var:`flags` in handle :var:`h`. The
+resulting handle flags will be a logical or of the old flags and the new.
+
+:func:`flux_flags_unset` clears open :var:`flags` in handle :var:`h`. The
+resulting handle flags will be a logical and of the old flags and the
+inverse of the new.
+
+:func:`flux_flags_get` can be used to retrieve the current open flags from
+handle :var:`h`.
+
+The valid flags are described in :man3:`flux_open`.
+
+
+RETURN VALUE
+============
+
+:func:`flux_flags_get` returns the current flags.
+
+
+ERRORS
+======
+
+These functions never fail.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_open`
diff --git a/doc/man3/flux_future_and_then.adoc b/doc/man3/flux_future_and_then.adoc
deleted file mode 100644
index 97a16c8eb0eb..000000000000
--- a/doc/man3/flux_future_and_then.adoc
+++ /dev/null
@@ -1,125 +0,0 @@
-flux_future_and_then(3)
-=======================
-:doctype: manpage
-
-
-NAME
-----
-flux_future_and_then, flux_future_or_then, flux_future_continue, flux_future_continue_error - functions for sequential composition of futures
-
-
-SYNOPSIS
---------
- #include
-
- flux_future_t *flux_future_and_then (flux_future_t *f,
- flux_continuation_f cb, void *arg);
- flux_future_t *flux_future_or_then (flux_future_t *f,
- flux_continuation_f cb, void *arg);
-
- int flux_future_continue (flux_future_t *prev, flux_future_t *f);
- void flux_future_continue_error (flux_future_t *prev, int errnum,
- const char *errstr);
-
-
-
-DESCRIPTION
------------
-
-See `flux_future_get(3)` for general functions that operate on futures,
-and `flux_future_create(3)` for a description of the `flux_future_t`
-base type. This page covers functions for the sequential composition of
-futures, i.e. chains of dependent futures.
-
-`flux_future_and_then(3)` is similar to `flux_future_then(3)`, but
-returns a future that may later be "continued" from the continuation
-callback `cb`. The provided continuation callback `cb` is only
-executed when the future argument `f` is fulfilled successfully. On
-error, the error from `f` is automatically propagated to the "next"
-future in the chain (returned by the function).
-
-`flux_future_and_then()` is useful when a series of asynchronous
-operations, each returning a `flux_future_t`, depend on the result
-of a previous operation. That is, `flux_future_and_then()` returns a
-placeholder future for an eventual future that can't be created until
-the continuation `cb` is run. The returned future can then be
-used as a synchronization handle or even passed to another
-`flux_future_and_then()` in the chain. By default, the next future
-in the chain will be fulfilled immediately using the result of the
-previous future after return from the callback `cb`. Most callbacks,
-however, should use either `flux_future_continue(3)` or
-`flux_future_continue_error(3)` to pass an intermediate future
-to use in fulfillment of the next future in the chain.
-
-`flux_future_or_then(3)` is like `flux_future_and_then()`, except
-the continuation callback `cb` is run when the future `f` is fulfilled
-with an error. This function is useful for recovery or other error
-handling (other than the default behavior of propagating an error
-down the chain to the final result). The `flux_future_or_then()`
-callback offers a chance to successfully fulfill the "next" future
-in the chain, even when the "previous" future was fulfilled with
-an error.
-
-As with `flux_future_and_then()` the continuation
-`cb` function for `flux_future_or_then()` should call
-`flux_future_continue()` or `flux_future_continue_error()`, or
-the result of the previous future will be propagated immediately
-to the next future in the chain.
-
-`flux_future_continue(3)` continues the next future embedded in `prev`
-(created by `flux_future_and_then()` or `flux_future_or_then()`) with
-the eventual result of the provided future `f`. This allows a future
-that was not created until the context of the callback to continue
-a sequential chain of futures created earlier. After the call to
-`flux_future_continue(3)` completes, the future `prev` may safely be
-destroyed. `flux_future_continue(3)` may be called with `f` equal
-to `NULL` if the caller desires the next future in the chain to
-*not* be fulfilled, in order to disable the automatic fulfillment
-that normally occurs for non-continued futures after the callback
-completes.
-
-`flux_future_continue_error(3)` is like `flux_future_continue()`
-but immediately fulfills the next future in the chain with an error and
-an optional error string. Once `flux_future_continue_error(3)`
-completes, the future `prev` may safely be destroyed.
-
-RETURN VALUE
-------------
-
-`flux_future_and_then()` and `flux_future_or_then()` return a `flux_future_t`
-on success, or NULL on error. If both functions are called on the same
-future, the returned `flux_future_t` from each will be the same object.
-
-`flux_future_continue()` returns 0 on success, or -1 on error with errno
-set.
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-EINVAL::
-Invalid argument.
-
-ENOENT::
-The requested object is not found.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_future_get(3), flux_future_create(3)
diff --git a/doc/man3/flux_future_and_then.rst b/doc/man3/flux_future_and_then.rst
new file mode 100644
index 000000000000..437d7a9f5c8e
--- /dev/null
+++ b/doc/man3/flux_future_and_then.rst
@@ -0,0 +1,141 @@
+=======================
+flux_future_and_then(3)
+=======================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_future_t *flux_future_and_then (flux_future_t *f,
+ flux_continuation_f cb,
+ void *arg);
+
+ flux_future_t *flux_future_or_then (flux_future_t *f,
+ flux_continuation_f cb,
+ void *arg);
+
+ int flux_future_continue (flux_future_t *prev,
+ flux_future_t *f);
+
+ void flux_future_continue_error (flux_future_t *prev,
+ int errnum,
+ const char *errstr);
+
+ int flux_future_fulfill_next (flux_future_t *f,
+ void *result,
+ flux_free_f free_fn);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+See :man3:`flux_future_get` for general functions that operate on futures,
+and :man3:`flux_future_create` for a description of the :type:`flux_future_t`
+base type. This page covers functions for the sequential composition of
+futures, i.e. chains of dependent futures.
+
+:func:`flux_future_and_then` is similar to :man3:`flux_future_then`, but
+returns a future that may later be "continued" from the continuation
+callback :var:`cb`. The provided continuation callback :var:`cb` is only
+executed when the future argument :var:`f` is fulfilled successfully. On
+error, the error from :var:`f` is automatically propagated to the "next"
+future in the chain (returned by the function).
+
+:func:`flux_future_and_then` is useful when a series of asynchronous
+operations, each returning a :type:`flux_future_t`, depend on the result
+of a previous operation. That is, :func:`flux_future_and_then` returns a
+placeholder future for an eventual future that can't be created until
+the continuation :var:`cb` is run. The returned future can then be
+used as a synchronization handle or even passed to another
+:func:`flux_future_and_then` in the chain. By default, the next future
+in the chain will be fulfilled immediately using the result of the
+previous future after return from the callback :var:`cb`. Most callbacks,
+however, should use either :func:`flux_future_continue` or
+:func:`flux_future_continue_error` to pass an intermediate future
+to use in fulfillment of the next future in the chain.
+
+:func:`flux_future_or_then` is like :func:`flux_future_and_then`, except
+the continuation callback :var:`cb` is run when the future :var:`f` is fulfilled
+with an error. This function is useful for recovery or other error
+handling (other than the default behavior of propagating an error
+down the chain to the final result). The :func:`flux_future_or_then`
+callback offers a chance to successfully fulfill the "next" future
+in the chain, even when the "previous" future was fulfilled with
+an error.
+
+As with :func:`flux_future_and_then` the continuation
+:var:`cb` function for :func:`flux_future_or_then` should call
+:func:`flux_future_continue` or :func:`flux_future_continue_error`, or
+the result of the previous future will be propagated immediately
+to the next future in the chain.
+
+:func:`flux_future_continue` continues the next future embedded in :var:`prev`
+(created by :func:`flux_future_and_then` or :func:`flux_future_or_then`) with
+the eventual result of the provided future :var:`f`. This allows a future
+that was not created until the context of the callback to continue
+a sequential chain of futures created earlier. After the call to
+:func:`flux_future_continue` completes, the future :var:`prev` may safely be
+destroyed. :func:`flux_future_continue` may be called with :var:`f` equal
+to ``NULL`` if the caller desires the next future in the chain to
+**not** be fulfilled, in order to disable the automatic fulfillment
+that normally occurs for non-continued futures after the callback
+completes.
+
+:func:`flux_future_continue_error` is like :func:`flux_future_continue`
+but immediately fulfills the next future in the chain with an error and
+an optional error string. Once :func:`flux_future_continue_error`
+completes, the future :var:`prev` may safely be destroyed.
+
+:func:`flux_future_fulfill_next` is like :man3:`flux_future_fulfill`, but
+fulfills the next future in the chain instead of the current future (which
+is presumably already fulfilled). This call is useful when a chained future
+is being used for post-processing a result from intermediate future-based
+calls, as it allows the next future to be fulfilled with a custom result,
+instead of with the value of another future as in
+:func:`flux_future_continue`.
+
+
+RETURN VALUE
+============
+
+:func:`flux_future_and_then` and :func:`flux_future_or_then` return a
+:type:`flux_future_t` on success, or NULL on error. If both functions are
+called on the same future, the returned :type:`flux_future_t` from each will
+be the same object.
+
+:func:`flux_future_continue` returns 0 on success, or -1 on error with errno
+set.
+
+:func:`flux_future_fulfill_next` returns 0 on success, or -1 with errno set
+to ``EINVAL`` if the target future does not have a next future to fulfill.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+EINVAL
+ Invalid argument.
+
+ENOENT
+ The requested object is not found.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_future_get`, :man3:`flux_future_create`
diff --git a/doc/man3/flux_future_create.adoc b/doc/man3/flux_future_create.adoc
deleted file mode 100644
index c06338b8fa90..000000000000
--- a/doc/man3/flux_future_create.adoc
+++ /dev/null
@@ -1,240 +0,0 @@
-flux_future_create(3)
-=====================
-:doctype: manpage
-
-
-NAME
-----
-flux_future_create, flux_future_fulfill, flux_future_fulfill_error, flux_future_fulfill_with, flux_future_aux_get, flux_future_aux_set, flux_future_set_flux, flux_future_get_flux - support methods for classes that return futures
-
-
-SYNOPSIS
---------
- #include
-
- typedef void (*flux_future_init_f)(flux_future_t *f,
- flux_reactor_t *r, void *arg);
-
- flux_future_t *flux_future_create (flux_future_init_f cb, void *arg);
-
- void flux_future_fulfill (flux_future_t *f,
- void *result, flux_free_f free_fn);
-
- void flux_future_fulfill_error (flux_future_t *f, int errnum,
- const char *errstr);
-
- void flux_future_fulfill_with (flux_future_t *f, flux_future_t *p);
-
- void flux_future_fatal_error (flux_future_t *f, int errnum,
- const char *errstr);
-
- void *flux_future_aux_get (flux_future_t *f, const char *name);
-
- int flux_future_aux_set (flux_future_t *f, const char *name,
- void *aux, flux_free_f destroy);
-
- void flux_future_set_reactor (flux_future_t *f, flux_t *h);
-
- flux_reactor_t *flux_future_get_reactor (flux_future_t *f);
-
- void flux_future_set_flux (flux_future_t *f, flux_t *h);
-
- flux_t *flux_future_get_flux (flux_future_t *f);
-
-
-DESCRIPTION
------------
-
-See `flux_future_get(3)` for general functions that operate on futures.
-This page covers functions primarily used when building classes that
-return futures.
-
-A Flux future represents some activity that may be completed with reactor
-watchers and/or message handlers. It is intended to be returned by other
-classes as a handle for synchronization and a container for results.
-This page describes the future interfaces used by such classes.
-
-A class that returns a future usually provides a creation function
-that internally calls `flux_future_create()`, and may provide functions
-to access class-specific result(s), that internally call `flux_future_get()`.
-The create function internally registers a _flux_future_init_f_
-function that is called lazily by the future implementation to perform
-class-specific reactor setup, such as installing watchers and message
-handlers.
-
-`flux_future_create()` creates a future and registers the
-class-specific initialization callback _cb_, and an opaque argument
-_arg_ that will be passed to _cb_. The purpose of the initialization
-callback is to set up class-specific watchers on a reactor obtained
-with `flux_future_get_reactor()`, or message handlers on a flux_t
-handle obtained with `flux_future_get_flux()`, or both.
-`flux_future_get_reactor()` and `flux_future_get_flux()` return
-different results depending on whether the initialization callback is
-triggered by a user calling `flux_future_then()` or
-`flux_future_wait_for()`. The function may be triggered in one or
-both contexts, at most once for each. The watchers or message
-handlers must eventually call `flux_future_fulfill()`,
-`flux_future_fulfill_error()`, or `flux_future_fatal_error()` to
-fulfill the future. See REACTOR CONTEXTS below for more information.
-
-`flux_future_fulfill()` fulfills the future, assigning an opaque
-_result_ value with optional destructor _free_fn_ to the future.
-A NULL _result_ is valid and also fulfills the future. The _result_
-is contained within the future and can be accessed with `flux_future_get()`
-as needed until the future is destroyed.
-
-`flux_future_fulfill_error()` fulfills the future, assigning an
-_errnum_ value and an optional error string. After the future is
-fulfilled with an error, `flux_future_get()` will return -1 with errno
-set to _errnum_.
-
-`flux_future_fulfill_with()` fulfills the target future _f_ using a
-fulfilled future _p_. This function copies the pending result or error
-from _p_ into _f_, and adds read-only access to the _aux_ items for _p_
-from _f_. This ensures that any `get` method which requires _aux_ items
-for _p_ will work with _f_. This function takes a reference to the source
-future _p_, so it safe to call `flux_future_destroy (p)` after this call.
-`flux_future_fulfill_with()` returns -1 on error with _errno_
-set on failure.
-
-`flux_future_fulfill()`, `flux_future_fulfill_with()`, and
-`flux_future_fulfill_error()` can be called multiple times to queue
-multiple results or errors. When callers access future results via
-`flux_future_get()`, results or errors will be returned in FIFO order.
-It is an error to call `flux_future_fulfill_with()` multiple times on
-the same target future _f_ with a different source future _p_.
-
-`flux_future_fatal_error()` fulfills the future, assigning an _errnum_
-value and an optional error string. Unlike
-`flux_future_fulfill_error()` this fulfillment can only be called once
-and takes precedence over all other fulfillments. It is used for
-catastrophic error paths in future fulfillment.
-
-`flux_future_aux_set()` attaches application-specific data
-to the parent object _f_. It stores data _aux_ by key _name_,
-with optional destructor _destroy_. The destructor, if non-NULL,
-is called when the parent object is destroyed, or when
-_key_ is overwritten by a new value. If _aux_ is NULL,
-the destructor for a previous value, if any is called,
- but no new value is stored. If _name_ is NULL,
-_aux_ is stored anonymously.
-
-`flux_future_aux_get()` retrieves application-specific data
-by _name_. If the data was stored anonymously, it
-cannot be retrieved.
-
-Names beginning with "flux::" are reserved for internal use.
-
-`flux_future_set_reactor()` may be used to associate a Flux reactor
-with a future. The reactor (or a temporary one, depending on the context)
-may be retrieved using `flux_future_get_reactor()`.
-
-`flux_future_set_flux()` may be used to associate a Flux broker handle
-with a future. The handle (or a clone associated with a temporary reactor,
-depending on the context) may be retrieved using `flux_future_get_flux()`.
-
-Futures may "contain" other futures, to arbitrary depth. That is, an
-init callback may create futures and use their continuations to fulfill
-the containing future in the same manner as reactor watchers and message
-handlers.
-
-
-REACTOR CONTEXTS
-----------------
-
-Internally, a future can operate in two reactor contexts. The initialization
-callback may be called in either or both contexts, depending on which
-synchronization functions are called by the user. `flux_future_get_reactor()`
-and `flux_future_get_flux()` return a result that depends on which context
-they are called from.
-
-When the user calls `flux_future_then()`, this triggers a call to the
-initialization callback. The callback would typically call
-`flux_future_get_reactor()` and/or `flux_future_get_flux()` to obtain the
-reactor or flux_t handle to be used to set up watchers or message handlers.
-In this context, the reactor or flux_t handle are exactly the ones passed
-to `flux_future_set_reactor()` and `flux_future_set_flux()`.
-
-When the user calls `flux_future_wait_for()`, this triggers the creation
-of a temporary reactor, then a call to the initialization callback.
-The temporary reactor allows these functions to wait _only_ for the future's
-events, without allowing unrelated watchers registered in the main reactor
-to run, which might complicate the application's control flow. In this
-context, `flux_future_get_reactor()` returns the temporary reactor, not
-the one passed in with `flux_future_set_reactor()`. `flux_future_get_flux()`
-returns a temporary flux_t handle cloned from the one passed to
-`flux_future_set_flux()`, and associated with the temporary reactor.
-After the internal reactor returns, any messages unmatched by the dispatcher
-on the cloned handle are requeued in the main flux_t handle with
-`flux_dispatch_requeue()`.
-
-Since the init callback may be made in either reactor context (at most once
-each), and is unaware of which context that is, it should take care when
-managing any context-specific state not to overwrite the state from a prior
-call. The ability to attach objects with destructors anonymously to the future
-with `flux_future_aux_set()` may be useful for managing the life cycle
-of reactor watchers and message handlers created by init callbacks.
-
-
-RETURN VALUE
-------------
-
-`flux_future_create()` returns a future on success. On error, NULL is
-returned and errno is set appropriately.
-
-`flux_future_aux_set()` returns zero on success. On error, -1 is
-returned and errno is set appropriately.
-
-`flux_future_aux_get()` returns the requested object on success. On
-error, NULL is returned and errno is set appropriately.
-
-`flux_future_get_flux()` returns a flux_t handle on success. On error,
-NULL is returned and errno is set appropriately.
-
-`flux_future_get_reactor()` returns a flux_reactor_t on success. On error,
-NULL is returned and errno is set appropriately.
-
-`flux_future_fulfill_with()` returns zero on success. On error, -1 is
-returned with errno set to EINVAL if either _f_ or _p_ is NULL, or
-_f_ and _p_ are the same, EAGAIN if the future _p_ is not ready, or
-EEXIST if the function is called multiple times with different _p_.
-
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-EINVAL::
-Invalid argument.
-
-ENOENT::
-The requested object is not found.
-
-EAGAIN::
-The requested operation is not ready. For `flux_future_fulfill_with()`,
-the target future _p_ is not fulfilled.
-
-EEXIST::
-`flux_future_fulfill_with()` was called multiple times with a different
-target future _p_.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_future_get(3), flux_clone(3)
diff --git a/doc/man3/flux_future_create.rst b/doc/man3/flux_future_create.rst
new file mode 100644
index 000000000000..59f40a97a054
--- /dev/null
+++ b/doc/man3/flux_future_create.rst
@@ -0,0 +1,243 @@
+=====================
+flux_future_create(3)
+=====================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ typedef void (*flux_future_init_f)(flux_future_t *f,
+ flux_reactor_t *r,
+ void *arg);
+
+ flux_future_t *flux_future_create (flux_future_init_f cb, void *arg);
+
+ void flux_future_fulfill (flux_future_t *f,
+ void *result,
+ flux_free_f free_fn);
+
+ void flux_future_fulfill_error (flux_future_t *f,
+ int errnum,
+ const char *errstr);
+
+ void flux_future_fulfill_with (flux_future_t *f, flux_future_t *p);
+
+ void flux_future_fatal_error (flux_future_t *f,
+ int errnum,
+ const char *errstr);
+
+ void *flux_future_aux_get (flux_future_t *f, const char *name);
+
+ int flux_future_aux_set (flux_future_t *f,
+ const char *name,
+ void *aux,
+ flux_free_f destroy);
+
+ void flux_future_set_reactor (flux_future_t *f, flux_t *h);
+
+ flux_reactor_t *flux_future_get_reactor (flux_future_t *f);
+
+ void flux_future_set_flux (flux_future_t *f, flux_t *h);
+
+ flux_t *flux_future_get_flux (flux_future_t *f);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+See :man3:`flux_future_get` for general functions that operate on futures.
+This page covers functions primarily used when building classes that
+return futures.
+
+A Flux future represents some activity that may be completed with reactor
+watchers and/or message handlers. It is intended to be returned by other
+classes as a handle for synchronization and a container for results.
+This page describes the future interfaces used by such classes.
+
+A class that returns a future usually provides a creation function that
+internally calls :func:`flux_future_create`, and may provide functions to
+access class-specific result(s), that internally call :man3:`flux_future_get`.
+The create function internally registers a :type:`flux_future_init_f`
+function that is called lazily by the future implementation to perform
+class-specific reactor setup, such as installing watchers and message
+handlers.
+
+:func:`flux_future_create` creates a future and registers the
+class-specific initialization callback :var:`cb`, and an opaque argument
+:var:`arg` that will be passed to :var:`cb`. The purpose of the initialization
+callback is to set up class-specific watchers on a reactor obtained
+with :func:`flux_future_get_reactor`, or message handlers on a :type:`flux_t`
+handle obtained with :func:`flux_future_get_flux`, or both.
+:func:`flux_future_get_reactor` and :func:`flux_future_get_flux` return
+different results depending on whether the initialization callback is
+triggered by a user calling :man3:`flux_future_then` or
+:man3:`flux_future_wait_for`. The function may be triggered in one or
+both contexts, at most once for each. The watchers or message
+handlers must eventually call :func:`flux_future_fulfill`,
+:func:`flux_future_fulfill_error`, or :func:`flux_future_fatal_error` to
+fulfill the future. See REACTOR CONTEXTS below for more information.
+
+:func:`flux_future_fulfill` fulfills the future, assigning an opaque
+:var:`result` value with optional destructor :var:`free_fn` to the future.
+A NULL :var:`result` is valid and also fulfills the future. The :var:`result`
+is contained within the future and can be accessed with :man3:`flux_future_get`
+as needed until the future is destroyed.
+
+:func:`flux_future_fulfill_error` fulfills the future, assigning an
+:var:`errnum` value and an optional error string. After the future is
+fulfilled with an error, :man3:`flux_future_get` will return -1 with
+:var:`errno` set to :var:`errnum`.
+
+:func:`flux_future_fulfill_with` fulfills the target future :var:`f` using a
+fulfilled future :var:`p`. This function copies the pending result or error
+from :var:`p` into :var:`f`, and adds read-only access to the :var:`aux` items
+for :var:`p` from :var:`f`. This ensures that any ``get`` method which requires
+:var:`aux` items for :var:`p` will work with :var:`f`. This function takes a
+reference to the source future :var:`p`, so it safe to call
+:man3:`flux_future_destroy` on :var:`p` after this call.
+:func:`flux_future_fulfill_with` returns -1 on error with :var:`errno`
+set on failure.
+
+:func:`flux_future_fulfill`, :func:`flux_future_fulfill_with`, and
+:func:`flux_future_fulfill_error` can be called multiple times to queue
+multiple results or errors. When callers access future results via
+:man3:`flux_future_get`, results or errors will be returned in FIFO order.
+It is an error to call :func:`flux_future_fulfill_with` multiple times on
+the same target future :var:`f` with a different source future :var:`p`.
+
+:func:`flux_future_fatal_error` fulfills the future, assigning an :var:`errnum`
+value and an optional error string. Unlike
+:func:`flux_future_fulfill_error` this fulfillment can only be called once
+and takes precedence over all other fulfillments. It is used for
+catastrophic error paths in future fulfillment.
+
+:func:`flux_future_aux_set` attaches application-specific data
+to the parent object :var:`f`. It stores data :var:`aux` by key :var:`name`,
+with optional destructor *destroy*. The destructor, if non-NULL,
+is called when the parent object is destroyed, or when
+:var:`key` is overwritten by a new value. If :var:`aux` is NULL,
+the destructor for a previous value, if any is called,
+but no new value is stored. If :var:`name` is NULL,
+:var:`aux` is stored anonymously.
+
+:func:`flux_future_aux_get` retrieves application-specific data
+by :var:`name`. If the data was stored anonymously, it
+cannot be retrieved.
+
+Names beginning with "flux::" are reserved for internal use.
+
+:func:`flux_future_set_reactor` may be used to associate a Flux reactor
+with a future. The reactor (or a temporary one, depending on the context)
+may be retrieved using :func:`flux_future_get_reactor`.
+
+:func:`flux_future_set_flux` may be used to associate a Flux broker handle
+with a future. The handle (or a clone associated with a temporary reactor,
+depending on the context) may be retrieved using :func:`flux_future_get_flux`.
+
+Futures may "contain" other futures, to arbitrary depth. That is, an
+init callback may create futures and use their continuations to fulfill
+the containing future in the same manner as reactor watchers and message
+handlers.
+
+
+REACTOR CONTEXTS
+================
+
+Internally, a future can operate in two reactor contexts. The initialization
+callback may be called in either or both contexts, depending on which
+synchronization functions are called by the user.
+:func:`flux_future_get_reactor` and :func:`flux_future_get_flux` return a
+result that depends on which context they are called from.
+
+When the user calls :man3:`flux_future_then`, this triggers a call to the
+initialization callback. The callback would typically call
+:func:`flux_future_get_reactor` and/or :func:`flux_future_get_flux()` to obtain
+the reactor or :type:`flux_t` handle to be used to set up watchers or message
+handlers. In this context, the reactor or :type:`flux_t` handle are exactly
+the ones passed to :func:`flux_future_set_reactor` and
+:func:`flux_future_set_flux`.
+
+When the user calls :man3:`flux_future_wait_for`, this triggers the creation
+of a temporary reactor, then a call to the initialization callback.
+The temporary reactor allows these functions to wait *only* for the future's
+events, without allowing unrelated watchers registered in the main reactor
+to run, which might complicate the application's control flow. In this
+context, :func:`flux_future_get_reactor` returns the temporary reactor, not
+the one passed in with :func:`flux_future_set_reactor`.
+:func:`flux_future_get_flux` returns a temporary :type:`flux_t` handle cloned
+from the one passed to :func:`flux_future_set_flux`, and associated with the
+temporary reactor.
+After the internal reactor returns, any messages unmatched by the dispatcher
+on the cloned handle are requeued in the main :type:`flux_t` handle with
+:func:`flux_dispatch_requeue`.
+
+Since the init callback may be made in either reactor context (at most once
+each), and is unaware of which context that is, it should take care when
+managing any context-specific state not to overwrite the state from a prior
+call. The ability to attach objects with destructors anonymously to the future
+with :func:`flux_future_aux_set` may be useful for managing the life cycle
+of reactor watchers and message handlers created by init callbacks.
+
+
+RETURN VALUE
+============
+
+:func:`flux_future_create` returns a future on success. On error, NULL is
+returned and :var:`errno` is set appropriately.
+
+:func:`flux_future_aux_set` returns zero on success. On error, -1 is
+returned and :var:`errno` is set appropriately.
+
+:func:`flux_future_aux_get` returns the requested object on success. On
+error, NULL is returned and :var:`errno` is set appropriately.
+
+:func:`flux_future_get_flux` returns a :type:`flux_t` handle on success.
+On error, NULL is returned and :var:`errno` is set appropriately.
+
+:func:`flux_future_get_reactor` returns a :type:`flux_reactor_t` on success.
+On error, NULL is returned and :var:`errno` is set appropriately.
+
+:func:`flux_future_fulfill_with` returns zero on success. On error, -1 is
+returned with :var:`errno` set to EINVAL if either :var:`f` or :var:`p` is
+NULL, or :var:`f` and :var:`p` are the same, EAGAIN if the future :var:`p` is
+not ready, or EEXIST if the function is called multiple times with different
+:var:`p`.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+EINVAL
+ Invalid argument.
+
+ENOENT
+ The requested object is not found.
+
+EAGAIN
+ The requested operation is not ready. For :func:`flux_future_fulfill_with`,
+ the target future :var:`p` is not fulfilled.
+
+EEXIST
+ :func:`flux_future_fulfill_with` was called multiple times with a different
+ target future :var:`p`.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_future_get`, :man3:`flux_clone`
diff --git a/doc/man3/flux_future_get.adoc b/doc/man3/flux_future_get.adoc
deleted file mode 100644
index 7a2bbc3bdeec..000000000000
--- a/doc/man3/flux_future_get.adoc
+++ /dev/null
@@ -1,140 +0,0 @@
-flux_future_get(3)
-==================
-:doctype: manpage
-
-
-NAME
-----
-flux_future_get, flux_future_then, flux_future_wait_for, flux_future_reset, flux_future_destroy - synchronize an activity
-
-
-SYNOPSIS
---------
- #include
-
- typedef void (*flux_continuation_f)(flux_future_t *f, void *arg);
-
- int flux_future_get (flux_future_t *f, const void **result);
-
- int flux_future_then (flux_future_t *f, double timeout,
- flux_continuation_f cb, void *arg);
-
- int flux_future_wait_for (flux_future_t *f, double timeout);
-
- void flux_future_reset (flux_future_t *f);
-
- void flux_future_destroy (flux_future_t *f);
-
- bool flux_future_has_error (flux_future_t *f);
-
- const char *flux_future_error_string (flux_future_t *f);
-
-OVERVIEW
---------
-
-A Flux future represents some activity that may be completed with reactor
-watchers and/or message handlers. It is both a handle for synchronization
-and a container for the result. A Flux future is said to be "fulfilled"
-when a result is available in the future container, or a fatal error has
-occurred. Flux futures were inspired by similar constructs in other
-programming environments mentioned in RESOURCES, but are not a faithful
-implementation of any particular one.
-
-Generally other Flux classes return futures, and may provide class-specific
-access function for results. The functions described in this page can be
-used to access, synchronize, and destroy futures returned from any such class.
-Authors of classes that return futures are referred to `flux_future_create(3)`.
-
-DESCRIPTION
------------
-
-`flux_future_get()` accesses the result of a fulfilled future. If the
-future is not yet fulfilled, it calls `flux_future_wait_for()` internally
-with a negative _timeout_, causing it to block until the future is fulfilled.
-A pointer to the result is assigned to _result_ (caller must NOT free),
-or -1 is returned if the future was fulfilled with an error.
-
-`flux_future_then()` sets up a continuation callback _cb_ that is called
-with opaque argument _arg_ once the future is fulfilled. The continuation
-will normally use `flux_future_get()` or a class-specific access function
-to obtain the result from the future container without blocking. The
-continuation may call `flux_future_destroy()` or `flux_future_reset()`.
-If _timeout_ is non-negative, the future must be fulfilled within the
-specified amount of time or the timeout fulfills it with an error (errno
-set to ETIMEDOUT).
-
-`flux_future_wait_for()` blocks until the future is fulfilled, or _timeout_
-(if non-negative) expires. This function may be called multiple times,
-with different values for _timeout_. If the timeout expires before
-the future is fulfilled, an error is returned (errno set to ETIMEDOUT)
-but the future remains unfulfilled. If _timeout_ is zero, function times
-out immediately if the future has not already been fulfilled.
-
-`flux_future_reset()` unfulfills a future, invalidating any result stored
-in the container, and preparing it to be fulfilled once again. If a
-continuation was registered, it remains in effect for the next fulfillment,
-however any timeout will have been cleared by the current fulfillment
-and must be re-established by following the `flux_future_reset()` with
-another `flux_future_then()`, if desired.
-
-`flux_future_destroy()` destroys a future, including any result contained
-within.
-
-`flux_future_has_error()` tests if an error exists in the future or not.
-It can be useful for determining if an error exists in a future or in
-other parts of code that may wrap around a future. It is commonly
-called before calling `flux_future_error_string()`.
-
-`flux_future_error_string()` returns the error string stored in a
-future. If the future was fulfilled with an optional error string,
-`flux_future_error_string()` will return that string. Otherwise, it
-will return the string associated with the error number set in a
-future. If the future is a NULL pointer, not fulfilled, or fulfilled
-with a non-error, NULL is returned.
-
-RETURN VALUE
-------------
-
-`flux_future_then()`, `flux_future_get()`, and `flux_future_wait_for()`
-return zero on success. On error, -1 is returned, and errno is set
-appropriately.
-
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-EINVAL::
-Invalid argument.
-
-ETIMEDOUT::
-A timeout passed to `flux_future_wait_for()` expired before the future
-was fulfilled.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-C++ std::future:
-
-Java util.concurrent.Future:
-
-Python3 concurrent.futures:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_future_create (3)
diff --git a/doc/man3/flux_future_get.rst b/doc/man3/flux_future_get.rst
new file mode 100644
index 000000000000..9253fe9fd047
--- /dev/null
+++ b/doc/man3/flux_future_get.rst
@@ -0,0 +1,140 @@
+==================
+flux_future_get(3)
+==================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ typedef void (*flux_continuation_f)(flux_future_t *f, void *arg);
+
+ int flux_future_get (flux_future_t *f, const void **result);
+
+ int flux_future_then (flux_future_t *f,
+ double timeout,
+ flux_continuation_f cb,
+ void *arg);
+
+ int flux_future_wait_for (flux_future_t *f, double timeout);
+
+ void flux_future_reset (flux_future_t *f);
+
+ void flux_future_destroy (flux_future_t *f);
+
+ bool flux_future_has_error (flux_future_t *f);
+
+ const char *flux_future_error_string (flux_future_t *f);
+
+Link with :command:`-lflux-core`.
+
+OVERVIEW
+========
+
+A Flux future represents some activity that may be completed with reactor
+watchers and/or message handlers. It is both a handle for synchronization
+and a container for the result. A Flux future is said to be "fulfilled"
+when a result is available in the future container, or a fatal error has
+occurred. Flux futures were inspired by similar constructs in other
+programming environments mentioned in RESOURCES, but are not a faithful
+implementation of any particular one.
+
+Generally other Flux classes return futures, and may provide class-specific
+access function for results. The functions described in this page can be
+used to access, synchronize, and destroy futures returned from any such class.
+Authors of classes that return futures are referred to :man3:`flux_future_create`.
+
+
+DESCRIPTION
+===========
+
+:func:`flux_future_get` accesses the result of a fulfilled future. If the
+future is not yet fulfilled, it calls :func:`flux_future_wait_for` internally
+with a negative :var:`timeout`, causing it to block until the future is
+fulfilled. A pointer to the result is assigned to :var:`result` (caller must
+NOT free), or -1 is returned if the future was fulfilled with an error.
+
+:func:`flux_future_then` sets up a continuation callback :var:`cb` that is
+called with opaque argument :var:`arg` once the future is fulfilled. The
+continuation will normally use :func:`flux_future_get` or a class-specific
+access function to obtain the result from the future container without
+blocking. The continuation may call :func:`flux_future_destroy` or
+:func:`flux_future_reset`.
+If :var:`timeout` is non-negative, the future must be fulfilled within the
+specified amount of time or the timeout fulfills it with an error (:var:`errno`
+set to ETIMEDOUT).
+
+:func:`flux_future_wait_for` blocks until the future is fulfilled, or
+:var:`timeout` (if non-negative) expires. This function may be called multiple
+times, with different values for :var:`timeout`. If the timeout expires before
+the future is fulfilled, an error is returned (:var:`errno` set to ETIMEDOUT)
+but the future remains unfulfilled. If :var:`timeout` is zero, function times
+out immediately if the future has not already been fulfilled.
+
+:func:`flux_future_reset` unfulfills a future, invalidating any result stored
+in the container, and preparing it to be fulfilled once again. If a
+continuation was registered, it remains in effect for the next fulfillment.
+If a timeout was specified when the continuation was registered, it is
+restarted.
+
+:func:`flux_future_destroy` destroys a future, including any result contained
+within.
+
+:func:`flux_future_has_error` tests if an error exists in the future or not.
+It can be useful for determining if an error exists in a future or in
+other parts of code that may wrap around a future. It is commonly
+called before calling :func:`flux_future_error_string`.
+
+:func:`flux_future_error_string` returns the error string stored in a
+future. If the future was fulfilled with an optional error string,
+:func:`flux_future_error_string` will return that string. Otherwise, it
+will return the string associated with the error number set in a
+future. If the future is a NULL pointer, not fulfilled, or fulfilled
+with a non-error, NULL is returned.
+
+
+RETURN VALUE
+============
+
+:func:`flux_future_then`, :func:`flux_future_get`, and
+:func:`flux_future_wait_for` return zero on success. On error, -1 is returned,
+and :var:`errno` is set appropriately.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+EINVAL
+ Invalid argument.
+
+ETIMEDOUT
+ A timeout passed to :func:`flux_future_wait_for` expired before the future
+ was fulfilled.
+
+EDEADLOCK (or EDEADLK on BSD systems)
+ :func:`flux_future_wait_for` would likely deadlock due to an
+ improperly initialized future.
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+C++ std::future: http://en.cppreference.com/w/cpp/thread/future
+
+Java ``util.concurrent.Future``: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html
+
+Python3 concurrent.futures: https://docs.python.org/3/library/concurrent.futures.html
+
+
+SEE ALSO
+========
+
+:man3:`flux_future_create`
diff --git a/doc/man3/flux_future_wait_all_create.adoc b/doc/man3/flux_future_wait_all_create.adoc
deleted file mode 100644
index 1e2f4fe02cab..000000000000
--- a/doc/man3/flux_future_wait_all_create.adoc
+++ /dev/null
@@ -1,126 +0,0 @@
-flux_future_wait_all_create(3)
-==============================
-:doctype: manpage
-
-
-NAME
-----
-flux_future_wait_all_create, flux_future_wait_any_create, flux_future_push, flux_future_first_child, flux_future_next_child, flux_future_get_child - functions for future composition
-
-
-SYNOPSIS
---------
- #include
-
- flux_future_t *flux_future_wait_all_create (void);
- flux_future_t *flux_future_wait_any_create (void);
-
- int flux_future_push (flux_future_t *cf, const char *name, flux_future_t *f);
-
- const char *flux_future_first_child (flux_future_t *cf);
- const char *flux_future_next_child (flux_future_t *cf);
- flux_future_t *flux_future_get_child (flux_future_t *cf, const char *name);
-
-
-DESCRIPTION
------------
-
-See `flux_future_get(3)` for general functions that operate on futures,
-and `flux_future_create(3)` for a description of the `flux_future_t`
-base type. This page covers functions used for composing futures into
-composite types using containers that allow waiting on all or any of a
-set of child futures.
-
-`flux_future_wait_all_create(3)` creates a future that is an empty
-container for other futures, which can subsequently be pushed into
-the container using `flux_future_push(3)`. The returned future will
-be automatically fulfilled when *all* children futures have been
-fulfilled. The caller may then use `flux_future_first_child(3)`,
-`flux_future_next_child(3)`, and/or `flux_future_get_child(3)` and
-expect that `flux_future_get(3)` will not block for any of these child
-futures. This function is useful to synchronize on a series of futures
-that may be run in parallel.
-
-`flux_future_wait_any_create(3)` creates a composite future that will be
-fulfilled once *any* one of its children are fulfilled. Once the composite
-future is fulfilled, the caller will need to traverse the child futures
-to determine which was fulfilled. This function is useful to synchronize
-on work where any one of several results is sufficient to continue.
-
-`flux_future_push(3)` places a new child future `f` into a future
-composite created by either `flux_future_wait_all_create(3)` or
-`flux_future_wait_any_create(3)`. A `name` is provided for the child so
-that the child future can be easily differentiated from other futures
-inside the container once the composite future is fulfilled.
-
-Once a `flux_future_t` is pushed onto a composite future with
-`flux_future_push(3)`, the memory for the child future is "adopted" by
-the new parent. Thus, calling `flux_future_destroy(3)` on the parent
-composite will destroy all children. Therefore, child futures that
-have been the target of `flux_future_push(3)` should *not* have
-flux_future_destroy(3)` called upon them to avoid double-free.
-
-`flux_future_first_child(3)` and `flux_future_next_child(3)` are used to
-iterate over child future names in a composite future created with either
-`flux_future_wait_all_create(3)` or `flux_future_wait_any_create(3)`. The
-`flux_future_t` corresponding to the returned _name_ can be then
-fetched with `flux_future_get_child(3)`. `flux_future_next_child` will
-return a `NULL` once all children have been iterated.
-
-
-`flux_future_get_child(3)` retrieves a child future from a composite
-by name.
-
-
-
-RETURN VALUE
-------------
-
-`flux_future_wait_any_create()` and `flux_future_wait_all_create()` return
-a future on success. On error, NULL is returned and errno is set appropriately.
-
-`flux_future_push()` returns zero on success. On error, -1 is
-returned and errno is set appropriately.
-
-`flux_future_first_child()` returns the name of the first child future in
-the targeted composite in no given order. If the composite is empty,
-a NULL is returned.
-
-`flux_future_next_child()` returns the name of the next child future in the
-targeted composite in no given order. If the last child has already been
-returned then this function returns NULL.
-
-`flux_future_get_child()` returns a `flux_future_t` corresponding to the
-child future with the supplied string `name` parameter. If no future with
-that name is a child of the composite, then the function returns NULL.
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-EINVAL::
-Invalid argument.
-
-ENOENT::
-The requested object is not found.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_future_get(3), flux_future_create(3)
diff --git a/doc/man3/flux_future_wait_all_create.rst b/doc/man3/flux_future_wait_all_create.rst
new file mode 100644
index 000000000000..647ff94fc746
--- /dev/null
+++ b/doc/man3/flux_future_wait_all_create.rst
@@ -0,0 +1,125 @@
+==============================
+flux_future_wait_all_create(3)
+==============================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_future_t *flux_future_wait_all_create (void);
+
+ flux_future_t *flux_future_wait_any_create (void);
+
+ int flux_future_push (flux_future_t *cf,
+ const char *name,
+ flux_future_t *f);
+
+ const char *flux_future_first_child (flux_future_t *cf);
+
+ const char *flux_future_next_child (flux_future_t *cf);
+
+ flux_future_t *flux_future_get_child (flux_future_t *cf,
+ const char *name);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+See :man3:`flux_future_get` for general functions that operate on futures,
+and :man3:`flux_future_create` for a description of the :type:`flux_future_t`
+base type. This page covers functions used for composing futures into
+composite types using containers that allow waiting on all or any of a
+set of child futures.
+
+:func:`flux_future_wait_all_create` creates a future that is an empty
+container for other futures, which can subsequently be pushed into
+the container using :func:`flux_future_push`. The returned future will
+be automatically fulfilled when **all** children futures have been
+fulfilled. The caller may then use :func:`flux_future_first_child`,
+:func:`flux_future_next_child`, and/or :func:`flux_future_get_child` and
+expect that :man3:`flux_future_get` will not block for any of these child
+futures. This function is useful to synchronize on a series of futures
+that may be run in parallel.
+
+:func:`flux_future_wait_any_create` creates a composite future that will be
+fulfilled once **any** one of its children are fulfilled. Once the composite
+future is fulfilled, the caller will need to traverse the child futures
+to determine which was fulfilled. This function is useful to synchronize
+on work where any one of several results is sufficient to continue.
+
+:func:`flux_future_push` places a new child future :var:`f` into a future
+composite created by either :func:`flux_future_wait_all_create` or
+:func:`flux_future_wait_any_create`. A :var:`name` is provided for the child so
+that the child future can be easily differentiated from other futures
+inside the container once the composite future is fulfilled.
+
+Once a :type:`flux_future_t` is pushed onto a composite future with
+:func:`flux_future_push`, the memory for the child future is "adopted" by
+the new parent. Thus, calling :man3:`flux_future_destroy` on the parent
+composite will destroy all children. Therefore, child futures that
+have been the target of :func:`flux_future_push` should **not** have
+:man3:`flux_future_destroy` called upon them to avoid double-free.
+
+:func:`flux_future_first_child` and :func:`flux_future_next_child` are used to
+iterate over child future names in a composite future created with either
+:func:`flux_future_wait_all_create` or :func:`flux_future_wait_any_create`. The
+:type:`flux_future_t` corresponding to the returned :var:`name` can be then
+fetched with :func:`flux_future_get_child`. :func:`flux_future_next_child` will
+return a ``NULL`` once all children have been iterated.
+
+:func:`flux_future_get_child` retrieves a child future from a composite
+by name.
+
+
+RETURN VALUE
+============
+
+:func:`flux_future_wait_any_create` and :func:`flux_future_wait_all_create`
+return a future on success. On error, NULL is returned and :var:`errno` is set
+appropriately.
+
+:func:`flux_future_push` returns zero on success. On error, -1 is
+returned and :var:`errno` is set appropriately.
+
+:func:`flux_future_first_child` returns the name of the first child future in
+the targeted composite in no given order. If the composite is empty,
+a NULL is returned.
+
+:func:`flux_future_next_child` returns the name of the next child future in the
+targeted composite in no given order. If the last child has already been
+returned then this function returns NULL.
+
+:func:`flux_future_get_child` returns a :type:`flux_future_t` corresponding to
+the child future with the supplied string :var:`name` parameter. If no future
+with that name is a child of the composite, then the function returns NULL.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+EINVAL
+ Invalid argument.
+
+ENOENT
+ The requested object is not found.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_future_get`, :man3:`flux_future_create`
diff --git a/doc/man3/flux_get_rank.adoc b/doc/man3/flux_get_rank.adoc
deleted file mode 100644
index 273bb666357e..000000000000
--- a/doc/man3/flux_get_rank.adoc
+++ /dev/null
@@ -1,69 +0,0 @@
-flux_get_rank(3)
-================
-:doctype: manpage
-
-
-NAME
-----
-flux_get_rank, flux_get_size - query Flux broker comms info
-
-
-SYNOPSIS
---------
-#include
-
-int flux_get_rank (flux_t *h, uint32_t *rank);
-
-int flux_get_size (flux_t *h, uint32_t *size);
-
-
-DESCRIPTION
------------
-
-`flux_get_rank()` and `flux_get_size()` ask the
-Flux broker for its rank in the comms session, and the size of the comms
-session.
-
-Session ranks are numbered 0 through size - 1.
-
-
-RETURN VALUE
-------------
-
-These functions return zero on success. On error, -1 is returned, and errno
-is set appropriately.
-
-
-ERRORS
-------
-
-EINVAL::
-Some arguments were invalid.
-
-EXAMPLES
---------
-
-Example:
-....
-include::tinfo.c[]
-....
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-https://github.com/flux-framework/rfc/blob/master/spec_3.adoc[RFC 3: CMB1 - Flux Comms Message Broker Protocol]
diff --git a/doc/man3/flux_get_rank.rst b/doc/man3/flux_get_rank.rst
new file mode 100644
index 000000000000..7b6d45c0ab95
--- /dev/null
+++ b/doc/man3/flux_get_rank.rst
@@ -0,0 +1,56 @@
+================
+flux_get_rank(3)
+================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ int flux_get_rank (flux_t *h, uint32_t *rank);
+
+ int flux_get_size (flux_t *h, uint32_t *size);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_get_rank` and :func:`flux_get_size` ask the
+Flux broker for its rank in the Flux instance, and the size of the Flux
+instance.
+
+Ranks are numbered 0 through size - 1.
+
+
+RETURN VALUE
+============
+
+These functions return zero on success. On error, -1 is returned, and errno
+is set appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ Some arguments were invalid.
+
+
+EXAMPLES
+========
+
+Example:
+
+.. literalinclude:: example/info.c
+ :language: c
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
diff --git a/doc/man3/flux_get_reactor.adoc b/doc/man3/flux_get_reactor.adoc
deleted file mode 100644
index 9db0910e25f4..000000000000
--- a/doc/man3/flux_get_reactor.adoc
+++ /dev/null
@@ -1,76 +0,0 @@
-flux_get_reactor(3)
-===================
-:doctype: manpage
-
-
-NAME
-----
-flux_get_reactor, flux_set_reactor - get/set reactor associated with broker handle
-
-
-SYNOPSIS
---------
-#include
-
-flux_reactor_t *flux_get_reactor (flux_t *h);
-
-int flux_set_reactor (flux_t *h, flux_reactor_t *r);
-
-
-DESCRIPTION
------------
-
-`flux_get_reactor()` retrieves a flux_reactor_t object previously
-associated with the broker handle _h_ by a call to `flux_set_reactor()`.
-If one has not been previously associated, a flux_reactor_t object is created
-on demand. If the flux_reactor_t object is created on demand, it will be
-destroyed when the handle is destroyed, otherwise it is the responsibility
-of the owner to destroy it after the handle is destroyed.
-
-`flux_set_reactor()` associates a flux_reactor_t object _r_ with a broker
-handle _h_. A flux_reactor_t object may be obtained from another handle,
-for example when events from multiple handles are to be managed using
-a common flux_reactor_t, or one may be created directly with
-`flux_reactor_create(3)`. `flux_set_reactor()` should be called
-immediately after `flux_open(3)` to avoid conflict with other API calls
-which may internally call `flux_get_reactor()`.
-
-
-RETURN VALUE
-------------
-
-`flux_get_reactor()` returns a flux_reactor_t object on success.
-On error, NULL is returned, and errno is set appropriately.
-
-`flux_set_reactor()` returns 0 on success, or -1 on failure with
-errno set appropriately.
-
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-EEXIST::
-Handle already has a reactor association.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_reactor_create(3), flux_reactor_destroy(3)
diff --git a/doc/man3/flux_get_reactor.rst b/doc/man3/flux_get_reactor.rst
new file mode 100644
index 000000000000..79e21a3600f2
--- /dev/null
+++ b/doc/man3/flux_get_reactor.rst
@@ -0,0 +1,69 @@
+===================
+flux_get_reactor(3)
+===================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_reactor_t *flux_get_reactor (flux_t *h);
+
+ int flux_set_reactor (flux_t *h, flux_reactor_t *r);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_get_reactor` retrieves a :type:`flux_reactor_t` object previously
+associated with the broker handle :var:`h` by a call to
+:func:`flux_set_reactor`. If one has not been previously associated,
+a :type:`flux_reactor_t` object is created on demand. If the
+:type:`flux_reactor_t` object is created on demand, it will be destroyed when
+the handle is destroyed, otherwise it is the responsibility of the owner to
+destroy it after the handle is destroyed.
+
+:func:`flux_set_reactor` associates a :type:`flux_reactor_t` object :var:`r`
+with a broker handle :var:`h`. A :type:`flux_reactor_t` object may be obtained
+from another handle, for example when events from multiple handles are to be
+managed using a common :type:`flux_reactor_t`, or one may be created directly
+with :man3:`flux_reactor_create`. :func:`flux_set_reactor` should be called
+immediately after :man3:`flux_open` to avoid conflict with other API calls
+which may internally call :func:`flux_get_reactor`.
+
+
+RETURN VALUE
+============
+
+:func:`flux_get_reactor` returns a :type:`flux_reactor_t` object on success.
+On error, NULL is returned, and :var:`errno` is set appropriately.
+
+:func:`flux_set_reactor` returns 0 on success, or -1 on failure with
+:var:`errno` set appropriately.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+EEXIST
+ Handle already has a reactor association.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_future_create`, :man3:`flux_reactor_destroy`
diff --git a/doc/man3/flux_handle_watcher_create.adoc b/doc/man3/flux_handle_watcher_create.adoc
deleted file mode 100644
index 537546aad460..000000000000
--- a/doc/man3/flux_handle_watcher_create.adoc
+++ /dev/null
@@ -1,91 +0,0 @@
-flux_handle_watcher_create(3)
-=============================
-:doctype: manpage
-
-
-NAME
-----
-flux_handle_watcher_create, flux_handle_watcher_get_flux - create broker handle watcher
-
-
-SYNOPSIS
---------
- #include
-
- typedef void (*flux_watcher_f)(flux_reactor_t *r,
- flux_watcher_t *w,
- int revents, void *arg);
-
- flux_watcher_t *flux_handle_watcher_create (flux_reactor_t *r,
- flux_t *h, int events,
- flux_watcher_f callback,
- void *arg);
-
- flux_t *flux_handle_watcher_get_flux (flux_watcher_t *w);
-
-
-DESCRIPTION
------------
-
-`flux_handle_watcher_create()` creates a flux_watcher_t object which
-monitors for events on a Flux broker handle _h_. When events occur,
-the user-supplied _callback_ is invoked.
-
-The _events_ and _revents_ arguments are a bitmask containing a
-logical ``or'' of the following bits. If a bit is set in _events_,
-it indicates interest in this type of event. If a bit is set in _revents_,
-it indicates that this event has occurred.
-
-FLUX_POLLIN::
-The handle is ready for reading.
-
-FLUX_POLLOUT::
-The handle is ready for writing.
-
-FLUX_POLLERR::
-The handle has encountered an error.
-This bit is ignored if it is set in _events_.
-
-Events are processed in a level-triggered manner. That is, the
-callback will continue to be invoked as long as the event has not been
-fully consumed or cleared, and the watcher has not been stopped.
-
-`flux_handle_watcher_get_flux()` is used to obtain the handle from
-within the callback.
-
-
-RETURN VALUE
-------------
-
-`flux_handle_watcher_create()` returns a flux_watcher_t object on success.
-On error, NULL is returned, and errno is set appropriately.
-
-`flux_handle_watcher_get_flux()` returns the handle associated with
-the watcher.
-
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_watcher_start(3), flux_reactor_start(3), flux_recv(3), flux_send(3).
diff --git a/doc/man3/flux_handle_watcher_create.rst b/doc/man3/flux_handle_watcher_create.rst
new file mode 100644
index 000000000000..365a33d1c49f
--- /dev/null
+++ b/doc/man3/flux_handle_watcher_create.rst
@@ -0,0 +1,86 @@
+=============================
+flux_handle_watcher_create(3)
+=============================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ typedef void (*flux_watcher_f)(flux_reactor_t *r,
+ flux_watcher_t *w,
+ int revents,
+ void *arg);
+
+ flux_watcher_t *flux_handle_watcher_create (flux_reactor_t *r,
+ flux_t *h,
+ int events,
+ flux_watcher_f callback,
+ void *arg);
+
+ flux_t *flux_handle_watcher_get_flux (flux_watcher_t *w);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_handle_watcher_create` creates a :type:`flux_watcher_t` object
+which monitors for events on a Flux broker handle :var:`h`. When events occur,
+the user-supplied :var:`callback` is invoked.
+
+The :var:`events` and :var:`revents` arguments are a bitmask containing a
+logical OR of the following bits. If a bit is set in :var:`events`,
+it indicates interest in this type of event. If a bit is set in :var:`revents`,
+it indicates that this event has occurred.
+
+FLUX_POLLIN
+ The handle is ready for reading.
+
+FLUX_POLLOUT
+ The handle is ready for writing.
+
+FLUX_POLLERR
+ The handle has encountered an error.
+ This bit is ignored if it is set in :var:`events`.
+
+Events are processed in a level-triggered manner. That is, the
+callback will continue to be invoked as long as the event has not been
+fully consumed or cleared, and the watcher has not been stopped.
+
+:func:`flux_handle_watcher_get_flux` is used to obtain the handle from
+within the callback.
+
+
+RETURN VALUE
+============
+
+:func:`flux_handle_watcher_create` returns a :type:`flux_watcher_t` object
+on success. On error, NULL is returned, and errno is set appropriately.
+
+:func:`flux_handle_watcher_get_flux` returns the handle associated with
+the watcher.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_watcher_start`, :man3:`flux_reactor_run`,
+:man3:`flux_recv`, :man3:`flux_send`
diff --git a/doc/man3/flux_idle_watcher_create.adoc b/doc/man3/flux_idle_watcher_create.adoc
deleted file mode 100644
index 8a589d4cadbe..000000000000
--- a/doc/man3/flux_idle_watcher_create.adoc
+++ /dev/null
@@ -1,88 +0,0 @@
-flux_idle_watcher_create(3)
-===========================
-:doctype: manpage
-
-
-NAME
-----
-flux_idle_watcher_create, flux_prepare_watcher_create, flux_check_watcher_create - create prepare/check/idle watchers
-
-
-SYNOPSIS
---------
- #include
-
- typedef void (*flux_watcher_f)(flux_reactor_t *r,
- flux_watcher_t *w,
- int revents, void *arg);
-
- flux_watcher_t *flux_prepare_watcher_create (flux_reactor_t *r,
- flux_watcher_f callback,
- void *arg);
-
- flux_watcher_t *flux_check_watcher_create (flux_reactor_t *r,
- flux_watcher_f callback,
- void *arg);
-
- flux_watcher_t *flux_idle_watcher_create (flux_reactor_t *r,
- flux_watcher_f callback,
- void *arg);
-
-
-DESCRIPTION
------------
-
-`flux_prepare_watcher_create()`, `flux_check_watcher_create()`, and
-`flux_idle_watcher_create()` create specialized reactor watchers with
-the following properties:
-
-The prepare watcher is called by the reactor loop immediately before
-blocking, while the check watcher is called by the reactor loop
-immediately after blocking.
-
-The idle watcher is always run when no other events are pending,
-excluding other idle watchers, prepare and check watchers.
-While it is active, the reactor loop does not block waiting for
-new events.
-
-The callback _revents_ argument should be ignored.
-
-Note: the Flux reactor is based on libev. For additional information
-on the behavior of these watchers, refer to the libev documentation on
-`ev_idle`, `ev_prepare`, and `ev_check`.
-
-
-RETURN VALUE
-------------
-
-These functions return a flux_watcher_t object on success.
-On error, NULL is returned, and errno is set appropriately.
-
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_watcher_start(3), flux_reactor_start(3)
-
-http://software.schmorp.de/pkg/libev.html[libev home page]
diff --git a/doc/man3/flux_idle_watcher_create.rst b/doc/man3/flux_idle_watcher_create.rst
new file mode 100644
index 000000000000..1ea5b23ddc9b
--- /dev/null
+++ b/doc/man3/flux_idle_watcher_create.rst
@@ -0,0 +1,81 @@
+===========================
+flux_idle_watcher_create(3)
+===========================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ typedef void (*flux_watcher_f)(flux_reactor_t *r,
+ flux_watcher_t *w,
+ int revents,
+ void *arg);
+
+ flux_watcher_t *flux_prepare_watcher_create (flux_reactor_t *r,
+ flux_watcher_f callback,
+ void *arg);
+
+ flux_watcher_t *flux_check_watcher_create (flux_reactor_t *r,
+ flux_watcher_f callback,
+ void *arg);
+
+ flux_watcher_t *flux_idle_watcher_create (flux_reactor_t *r,
+ flux_watcher_f callback,
+ void *arg);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_prepare_watcher_create`, :func:`flux_check_watcher_create`, and
+:func:`flux_idle_watcher_create` create specialized reactor watchers with
+the following properties:
+
+The prepare watcher is called by the reactor loop immediately before
+blocking, while the check watcher is called by the reactor loop
+immediately after blocking.
+
+The idle watcher is always run when no other events are pending,
+excluding other idle watchers, prepare and check watchers.
+While it is active, the reactor loop does not block waiting for
+new events.
+
+The callback :var:`revents` argument should be ignored.
+
+Note: the Flux reactor is based on libev. For additional information
+on the behavior of these watchers, refer to the libev documentation on
+``ev_idle``, ``ev_prepare``, and ``ev_check``.
+
+
+RETURN VALUE
+============
+
+These functions return a :type:`flux_watcher_t` object on success.
+On error, NULL is returned, and :var:`errno` is set appropriately.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+libev: http://software.schmorp.de/pkg/libev.html
+
+
+SEE ALSO
+========
+
+:man3:`flux_watcher_start`, :man3:`flux_reactor_run`, :man3:`flux_check_watcher_create`
diff --git a/doc/man3/flux_job_timeleft.rst b/doc/man3/flux_job_timeleft.rst
new file mode 100644
index 000000000000..e8cb972ebf56
--- /dev/null
+++ b/doc/man3/flux_job_timeleft.rst
@@ -0,0 +1,44 @@
+====================
+flux_job_timeleft(3)
+====================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ int flux_job_timeleft (flux_t *h,
+ flux_error_t *error,
+ double *timeleft);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+The :func:`flux_job_timeleft` function determines if the calling process
+is executing within the context of a Flux job (either a parallel job or
+a Flux instance running as a job), then handles querying the appropriate
+service for the remaining time in the job.
+
+RETURN VALUE
+============
+
+:func:`flux_job_timeleft` returns 0 on success with the remaining time in
+floating point seconds stored in :var:`timeleft`. If the job does not have
+an established time limit, then :var:`timeleft` is set to ``inf``. If the job
+time limit has expired or the job is no longer running, then :var:`timeleft`
+is set to ``0``.
+
+If the current process is not part of an active job or instance, or another
+error occurs, then this function returns ``-1`` with an error string set in
+``error->text``.
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
diff --git a/doc/man3/flux_jobtap_get_flux.rst b/doc/man3/flux_jobtap_get_flux.rst
new file mode 100644
index 000000000000..b7bd8a71087a
--- /dev/null
+++ b/doc/man3/flux_jobtap_get_flux.rst
@@ -0,0 +1,102 @@
+=======================
+flux_jobtap_get_flux(3)
+=======================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+ #include
+
+ flux_t *flux_jobtap_get_flux (flux_plugin_t *p);
+
+ int flux_jobtap_service_register (flux_plugin_t *p,
+ const char *method,
+ flux_msg_handler_f cb,
+ void *arg);
+
+ int flux_jobtap_reprioritize_all (flux_plugin_t *p);
+
+ int flux_jobtap_reprioritize_job (flux_plugin_t *p,
+ flux_jobid_t id,
+ unsigned int priority);
+
+ int flux_jobtap_priority_unavail (flux_plugin_t *p,
+ flux_plugin_arg_t *args);
+
+ int flux_jobtap_reject_job (flux_plugin_t *p,
+ flux_plugin_arg_t *args,
+ const char *fmt,
+ ...);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+These interfaces are used by Flux *jobtap* plugins which are used to
+extend the job manager broker module.
+
+:func:`flux_jobtap_get_flux` returns the job manager's Flux handle given
+the plugin's :type:`flux_plugin_t`. This can be used by a *jobtap* plugin
+to send RPCs, schedule timer watchers, or other asynchronous work.
+
+:func:`flux_jobtap_service_register` registers a service name :var:`method`
+under the job manager which will be handled by the provided message
+handler :var:`cb`. The constructed service name will be
+``job-manager..`` where ``name`` is the name of the plugin
+as returned by :func:`flux_plugin_get_name`. As such, this call may
+fail if the *jobtap* plugin has not yet set a name for itself using
+:func:`flux_plugin_set_name`.
+
+:func:`flux_jobtap_reprioritize_all` requests that the job manager begin
+reprioritization of all pending jobs, i.e. jobs in the PRIORITY and
+SCHED states. This will result on each job having a ``job.priority.get``
+callback invoked on it.
+
+:func:`flux_jobtap_reprioritize_job` allows a *jobtap* plugin to asynchronously
+assign the priority of a job.
+
+:func:`flux_jobtap_priority_unavail` is a convenience function which may
+be used by a plugin in the ``job.state.priority`` priority callback to
+indicate that a priority for the job is not yet available. It can be
+called as::
+
+ return flux_jobtap_priority_unavail (p, args);
+
+:func:`flux_jobtap_reject_job` is a convenience function which may be used
+by a plugin from the ``job.validate`` callback to reject a job before its
+submission is fully complete. The error and optional message supplied in
+:var:`fmt` will be returned to the originating job submission request. This
+function returns ``-1`` so that it may be conveniently called as::
+
+ return flux_jobtap_reject_job (p, args,
+ "User exceeded %d jobs",
+ limit);
+
+RETURN VALUE
+============
+
+:func:`flux_jobtap_get_flux` returns a :type:`flux_t` handle on success.
+``NULL`` is returned with errno set to ``EINVAL`` if the supplied
+:type:`flux_plugin_t` argument is not a jobtap plugin handle.
+
+:func:`flux_jobtap_reject_job` always returns ``-1`` so that it may be used
+to exit the ``job.validate`` callback.
+
+The remaining functions return 0 on success, -1 on failure.
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man7:`flux-jobtap-plugins`
diff --git a/doc/man3/flux_kvs_commit.adoc b/doc/man3/flux_kvs_commit.adoc
deleted file mode 100644
index 999226a4e692..000000000000
--- a/doc/man3/flux_kvs_commit.adoc
+++ /dev/null
@@ -1,137 +0,0 @@
-flux_kvs_commit(3)
-==================
-:doctype: manpage
-
-
-NAME
-----
-flux_kvs_commit, flux_kvs_fence, flux_kvs_commit_get_treeobj, flux_kvs_commit_get_sequence - commit a KVS transaction
-
-
-SYNOPSIS
---------
- #include
-
- flux_future_t *flux_kvs_commit (flux_t *h,
- const char *ns,
- int flags,
- flux_kvs_txn_t *txn);
-
- flux_future_t *flux_kvs_fence (flux_t *h,
- const char *ns,
- int flags,
- const char *name,
- int nprocs,
- flux_kvs_txn_t *txn);
-
- int flux_kvs_commit_get_treeobj (flux_future_t *f,
- const char **treeobj);
-
- int flux_kvs_commit_get_sequence (flux_future_t *f,
- int *seq);
-
-DESCRIPTION
------------
-
-`flux_kvs_commit()` sends a request via handle _h_ to the KVS service
-to commit a transaction _txn_. _txn_ is created with
-`flux_kvs_txn_create(3)` and after commit completion, is destroyed
-with `flux_kvs_txn_destroy()`. A `flux_future_t` object is returned,
-which acts as handle for synchronization and container for the
-response. The _txn_ will operate in the namespace specified by _ns_.
-If _ns_ is NULL, `flux_kvs_commit()` will operate on the default
-namespace, or if set, the namespace from the FLUX_KVS_NAMESPACE
-environment variable. Note that all transactions operate on the same
-namespace.
-
-`flux_kvs_fence()` is a "collective" version of `flux_kvs_commit()` that
-supports multiple callers. Each caller uses the same _flags_, _name_,
-and _nprocs_ arguments. Once _nprocs_ requests are received by the KVS
-service for the named operation, the transactions are combined and committed
-together as one transaction. _name_ must be unique across the Flux session
-and should not be reused, even after the fence is complete.
-
-`flux_future_then(3)` may be used to register a reactor callback
-(continuation) to be called once the response to the commit/fence
-request has been received. `flux_future_wait_for(3)` may be used to
-block until the response has been received. Both accept an optional timeout.
-
-`flux_future_get()`, `flux_kvs_commit_get_treeobj()`, or
-`flux_kvs_commit_get_sequence()` can decode the response. A return of
-0 indicates success and the entire transaction was committed. A
-return of -1 indicates failure, none of the transaction was committed.
-All can be used on the `flux_future_t` returned by `flux_kvs_commit()`
-or `flux_kvs_fence()`.
-
-In addition to checking for success or failure,
-`flux_kvs_commit_get_treeobj()` and `flux_kvs_commit_get_sequence()`
-can return information about the root snapshot that the commit or
-fence has completed its transaction on.
-
-`flux_kvs_commit_get_treeobj()` obtains the root hash in the form of
-an RFC 11 _dirref_ treeobj, suitable to be passed to
-`flux_kvs_lookupat(3)`.
-
-`flux_kvs_commit_get_sequence()` retrieves the monotonic sequence number
-for the root.
-
-FLAGS
------
-
-The following are valid bits in a _flags_ mask passed as an argument
-to `flux_kvs_commit()` or `flux_kvs_fence()`.
-
-FLUX_KVS_NO_MERGE::
-The KVS service may merge contemporaneous commit transactions as an
-optimization. However, if the combined transactions modify the same key,
-a watch on that key may only be notified of the last-in value. This flag
-can be used to disable that optimization for this transaction.
-
-
-RETURN VALUE
-------------
-
-`flux_kvs_commit()` and `flux_kvs_fence()` return a `flux_future_t` on
-success, or NULL on failure with errno set appropriately.
-
-
-ERRORS
-------
-
-EINVAL::
-One of the arguments was invalid.
-
-ENOMEM::
-Out of memory.
-
-EPROTO::
-A request was malformed.
-
-ENOSYS::
-The KVS module is not loaded.
-
-ENOTSUP::
-An unknown namespace was requested.
-
-EOVERFLOW::
-`flux_kvs_fence()` has been called too many times and _nprocs_ has
-been exceeded.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_future_get(3), flux_kvs_txn_create(3), flux_kvs_set_namespace(3)
diff --git a/doc/man3/flux_kvs_commit.rst b/doc/man3/flux_kvs_commit.rst
new file mode 100644
index 000000000000..59b3e216c493
--- /dev/null
+++ b/doc/man3/flux_kvs_commit.rst
@@ -0,0 +1,133 @@
+==================
+flux_kvs_commit(3)
+==================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_future_t *flux_kvs_commit (flux_t *h,
+ const char *ns,
+ int flags,
+ flux_kvs_txn_t *txn);
+
+ flux_future_t *flux_kvs_fence (flux_t *h,
+ const char *ns,
+ int flags,
+ const char *name,
+ int nprocs,
+ flux_kvs_txn_t *txn);
+
+ int flux_kvs_commit_get_treeobj (flux_future_t *f,
+ const char **treeobj);
+
+ int flux_kvs_commit_get_sequence (flux_future_t *f, int *seq);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_kvs_commit` sends a request via handle :var:`h` to the KVS service
+to commit a transaction :var:`txn`. :var:`txn` is created with
+:man3:`flux_kvs_txn_create` and after commit completion, is destroyed
+with :man3:`flux_kvs_txn_destroy`. A :type:`flux_future_t` object is returned,
+which acts as handle for synchronization and container for the
+response. The :var:`txn` will operate in the namespace specified by :var:`ns`.
+If :var:`ns` is NULL, :func:`flux_kvs_commit` will operate on the default
+namespace, or if set, the namespace from the FLUX_KVS_NAMESPACE
+environment variable. Note that all transactions operate on the same
+namespace.
+
+:func:`flux_kvs_fence` is a "collective" version of :func:`flux_kvs_commit`
+that supports multiple callers. Each caller uses the same :var:`flags`,
+:var:`name`, and :var:`nprocs` arguments. Once :var:`nprocs` requests are
+received by the KVS service for the named operation, the transactions are
+combined and committed together as one transaction. :var:`name` must be unique
+across the Flux session and should not be reused, even after the fence is
+complete.
+
+:man3:`flux_future_then` may be used to register a reactor callback
+(continuation) to be called once the response to the commit/fence
+request has been received. :man3:`flux_future_wait_for` may be used to
+block until the response has been received. Both accept an optional timeout.
+
+:man3:`flux_future_get`, :func:`flux_kvs_commit_get_treeobj`, or
+:func:`flux_kvs_commit_get_sequence` can decode the response. A return of
+0 indicates success and the entire transaction was committed. A
+return of -1 indicates failure, none of the transaction was committed.
+All can be used on the :type:`flux_future_t` returned by :func:`flux_kvs_commit`
+or :func:`flux_kvs_fence`.
+
+In addition to checking for success or failure,
+:func:`flux_kvs_commit_get_treeobj` and :func:`flux_kvs_commit_get_sequence`
+can return information about the root snapshot that the commit or
+fence has completed its transaction on.
+
+:func:`flux_kvs_commit_get_treeobj` obtains the root hash in the form of
+an RFC 11 *dirref* treeobj, suitable to be passed to
+:man3:`flux_kvs_lookupat`.
+
+:func:`flux_kvs_commit_get_sequence` retrieves the monotonic sequence number
+for the root.
+
+
+FLAGS
+=====
+
+The following are valid bits in a :var:`flags` mask passed as an argument
+to :func:`flux_kvs_commit` or :func:`flux_kvs_fence`.
+
+FLUX_KVS_NO_MERGE
+ The KVS service may merge contemporaneous commit transactions as an
+ optimization. However, if the combined transactions modify the same key,
+ a watch on that key may only be notified of the last-in value. This flag
+ can be used to disable that optimization for this transaction.
+
+
+RETURN VALUE
+============
+
+:func:`flux_kvs_commit` and :func:`flux_kvs_fence` return a
+:type:`flux_future_t` on success, or NULL on failure with :var:`errno` set
+appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ One of the arguments was invalid.
+
+ENOMEM
+ Out of memory.
+
+EPROTO
+ A request was malformed.
+
+ENOSYS
+ The KVS module is not loaded.
+
+ENOTSUP
+ An unknown namespace was requested.
+
+EOVERFLOW
+ :func:`flux_kvs_fence` has been called too many times and :var:`nprocs` has
+ been exceeded.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_future_get`, :man3:`flux_kvs_txn_create`
diff --git a/doc/man3/flux_kvs_copy.adoc b/doc/man3/flux_kvs_copy.adoc
deleted file mode 100644
index 55e32a074069..000000000000
--- a/doc/man3/flux_kvs_copy.adoc
+++ /dev/null
@@ -1,108 +0,0 @@
-flux_kvs_copy(3)
-================
-:doctype: manpage
-
-
-NAME
-----
-flux_kvs_copy, flux_kvs_move - copy/move a KVS key
-
-
-SYNOPSIS
---------
- #include
-
- flux_future_t *flux_kvs_copy (flux_t *h,
- const char *srckey,
- const char *dstkey,
- int commit_flags);
-
- flux_future_t *flux_kvs_move (flux_t *h,
- const char *srckey,
- const char *dstkey,
- int commit_flags);
-
-
-DESCRIPTION
------------
-
-`flux_kvs_copy()` sends a request via handle _h_ to the KVS service
-to look up the directory entry of _srckey_. Upon receipt of the response,
-it then sends another request to commit a duplicate at _dstkey_.
-_commit_flags_ are passed through to the commit operation.
-See the FLAGS section of flux_kvs_commit(3).
-
-The net effect is that all content below _srckey_ is copied to _dstkey_.
-Due to the hash tree organization of the KVS name space, only the
-directory entry needs to be duplicated to create a new, fully independent
-deep copy of the original data.
-
-`flux_kvs_move()` first performs a `flux_kvs_copy()`, then sends a
-commit request to unlink _srckey_. _commit_flags_ are passed through to
-the commit within `flux_kvs_copy()`, and to the commit which performs
-the unlink.
-
-`flux_kvs_copy()` and `flux_kvs_move()` are capable of working across
-namespaces. See `flux_kvs_commit(3)` for info on how to select a
-namespace other than the default.
-
-
-CAVEATS
--------
-
-`flux_kvs_copy()` and `flux_kvs_commit()` are implemented as aggregates
-of multiple KVS operations. As such they do not have the "all or nothing"
-guarantee of a being carried out within a single KVS transaction.
-
-In the unlikely event that the copy phase of a `flux_kvs_move()`
-succeeds but the unlink phase fails, `flux_kvs_move()` may return failure
-without cleaning up the new copy. Since the copy phase already validated
-that the unlink target key exists by copying from it, the source of such a
-failure would be a transient error such as out of memory or communication
-failure.
-
-
-RETURN VALUE
-------------
-
-`flux_kvs_copy ()` and `flux_kvs_move ()` return a `flux_future_t` on
-success, or NULL on failure with errno set appropriately.
-
-
-ERRORS
-------
-
-EINVAL::
-One of the arguments was invalid.
-
-ENOMEM::
-Out of memory.
-
-EPROTO::
-A request was malformed.
-
-ENOSYS::
-The KVS module is not loaded.
-
-ENOTSUP::
-An unknown namespace was requested.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_future_get(3), flux_kvs_commit(3)
diff --git a/doc/man3/flux_kvs_copy.rst b/doc/man3/flux_kvs_copy.rst
new file mode 100644
index 000000000000..ce46b59b3f10
--- /dev/null
+++ b/doc/man3/flux_kvs_copy.rst
@@ -0,0 +1,100 @@
+================
+flux_kvs_copy(3)
+================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_future_t *flux_kvs_copy (flux_t *h,
+ const char *srckey,
+ const char *dstkey,
+ int commit_flags);
+
+ flux_future_t *flux_kvs_move (flux_t *h,
+ const char *srckey,
+ const char *dstkey,
+ int commit_flags);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_kvs_copy` sends a request via handle :var:`h` to the KVS service
+to look up the directory entry of :var:`srckey`. Upon receipt of the response,
+it then sends another request to commit a duplicate at :var:`dstkey`.
+:var:`commit_flags` are passed through to the commit operation.
+See the FLAGS section of :man3:`flux_kvs_commit`.
+
+The net effect is that all content below :var:`srckey` is copied to
+:var:`dstkey`. Due to the hash tree organization of the KVS name space, only
+the directory entry needs to be duplicated to create a new, fully independent
+deep copy of the original data.
+
+:func:`flux_kvs_move` first performs a :func:`flux_kvs_copy`, then sends a
+commit request to unlink :var:`srckey`. :var:`commit_flags` are passed through
+to the commit within :func:`flux_kvs_copy`, and to the commit which performs
+the unlink.
+
+:func:`flux_kvs_copy` and :func:`flux_kvs_move` are capable of working across
+namespaces. See :man3:`flux_kvs_commit` for info on how to select a
+namespace other than the default.
+
+
+CAVEATS
+=======
+
+:func:`flux_kvs_copy` and :func:`flux_kvs_commit` are implemented as aggregates
+of multiple KVS operations. As such they do not have the "all or nothing"
+guarantee of a being carried out within a single KVS transaction.
+
+In the unlikely event that the copy phase of a :func:`flux_kvs_move`
+succeeds but the unlink phase fails, :func:`flux_kvs_move` may return failure
+without cleaning up the new copy. Since the copy phase already validated
+that the unlink target key exists by copying from it, the source of such a
+failure would be a transient error such as out of memory or communication
+failure.
+
+
+RETURN VALUE
+============
+
+:func:`flux_kvs_copy` and :func:`flux_kvs_move` return a :type:`flux_future_t`
+on success, or NULL on failure with errno set appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ One of the arguments was invalid.
+
+ENOMEM
+ Out of memory.
+
+EPROTO
+ A request was malformed.
+
+ENOSYS
+ The KVS module is not loaded.
+
+ENOTSUP
+ An unknown namespace was requested.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_future_get`, :man3:`flux_kvs_commit`
diff --git a/doc/man3/flux_kvs_getroot.adoc b/doc/man3/flux_kvs_getroot.adoc
deleted file mode 100644
index 4b854594ec9e..000000000000
--- a/doc/man3/flux_kvs_getroot.adoc
+++ /dev/null
@@ -1,113 +0,0 @@
-flux_kvs_getroot(3)
-===================
-:doctype: manpage
-
-
-NAME
-----
-flux_kvs_getroot, flux_kvs_getroot_get_treeobj, flux_kvs_getroot_get_blobref, flux_kvs_getroot_get_sequence, flux_kvs_getroot_get_owner, flux_kvs_getroot_cancel - look up KVS root hash
-
-
-SYNOPSIS
---------
- #include
-
- flux_future_t *flux_kvs_getroot (flux_t *h,
- const char *ns,
- int flags);
-
- int flux_kvs_getroot_get_treeobj (flux_future_t *f,
- const char **treeobj);
-
- int flux_kvs_getroot_get_blobref (flux_future_t *f,
- const char **blobref);
-
- int flux_kvs_getroot_get_sequence (flux_future_t *f,
- int *seq);
-
- int flux_kvs_getroot_get_owner (flux_future_t *f,
- uint32_t *owner);
-
-
-DESCRIPTION
------------
-
-`flux_kvs_getroot()` sends a request via handle _h_ to the `kvs`
-service to look up the current root hash for namespace _ns_. A `flux_future_t`
-object is returned, which acts as handle for synchronization and container
-for the response. _flags_ is currently unused and should be set to 0.
-
-Upon future fulfillment, these functions can decode the result:
-
-`flux_kvs_getroot_get_treeobj()` obtains the root hash in the form
-of an RFC 11 _dirref_ treeobj, suitable to be passed to `flux_kvs_lookupat(3)`.
-
-`flux_kvs_getroot_get_blobref()` obtains the RFC 10 blobref, suitable to
-be passed to `flux_content_load(3)`.
-
-`flux_kvs_getroot_get_sequence()` retrieves the monotonic sequence number
-for the root.
-
-`flux_kvs_getroot_get_owner()` retrieves the namespace owner.
-
-
-FLAGS
------
-
-The _flags_ mask is currently unused and should be set to 0.
-
-
-RETURN VALUE
-------------
-
-`flux_kvs_getroot()` returns a `flux_future_t` on success, or NULL on
-failure with errno set appropriately.
-
-The other functions return zero on success, or -1 on failure with errno
-set appropriately.
-
-
-ERRORS
-------
-
-EINVAL::
-One of the arguments was invalid.
-
-ENOMEM::
-Out of memory.
-
-EPROTO::
-A request was malformed.
-
-ENOSYS::
-The kvs module is not loaded.
-
-ENOTSUP::
-An unknown namespace was requested or namespace was deleted.
-
-EPERM::
-The requesting user is not permitted to access the requested namespace.
-
-ENODATA::
-A stream of responses has been terminated by a call to
-`flux_kvs_getroot_cancel()`.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_kvs_lookup (3), flux_future_get (3), flux_content_load (3).
diff --git a/doc/man3/flux_kvs_getroot.rst b/doc/man3/flux_kvs_getroot.rst
new file mode 100644
index 000000000000..caf38ea71cf7
--- /dev/null
+++ b/doc/man3/flux_kvs_getroot.rst
@@ -0,0 +1,104 @@
+===================
+flux_kvs_getroot(3)
+===================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_future_t *flux_kvs_getroot (flux_t *h,
+ const char *ns,
+ int flags);
+
+ int flux_kvs_getroot_get_treeobj (flux_future_t *f,
+ const char **treeobj);
+
+ int flux_kvs_getroot_get_blobref (flux_future_t *f,
+ const char **blobref);
+
+ int flux_kvs_getroot_get_sequence (flux_future_t *f, int *seq);
+
+ int flux_kvs_getroot_get_owner (flux_future_t *f, uint32_t *owner);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_kvs_getroot` sends a request via handle :var:`h` to the ``kvs``
+service to look up the current root hash for namespace :var:`ns`. A
+:type:`flux_future_t` object is returned, which acts as handle for
+synchronization and container for the response. :var:`flags` is currently
+unused and should be set to 0.
+
+Upon future fulfillment, these functions can decode the result:
+
+:func:`flux_kvs_getroot_get_treeobj` obtains the root hash in the form
+of an RFC 11 *dirref* treeobj, suitable to be passed to :man3:`flux_kvs_lookupat`.
+
+:func:`flux_kvs_getroot_get_blobref` obtains the RFC 10 blobref, suitable to
+be passed to :man3:`flux_content_load`.
+
+:func:`flux_kvs_getroot_get_sequence` retrieves the monotonic sequence number
+for the root.
+
+:func:`flux_kvs_getroot_get_owner` retrieves the namespace owner.
+
+
+FLAGS
+=====
+
+The :var:`flags` mask is currently unused and should be set to 0.
+
+
+RETURN VALUE
+============
+
+:func:`flux_kvs_getroot` returns a :type:`flux_future_t` on success, or NULL
+on failure with :var:`errno` set appropriately.
+
+The other functions return zero on success, or -1 on failure with :var:`errno`
+set appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ One of the arguments was invalid.
+
+ENOMEM
+ Out of memory.
+
+EPROTO
+ A request was malformed.
+
+ENOSYS
+ The kvs module is not loaded.
+
+ENOTSUP
+ An unknown namespace was requested or namespace was deleted.
+
+EPERM
+ The requesting user is not permitted to access the requested namespace.
+
+ENODATA
+ A stream of responses has been terminated by a call to
+ :func:`flux_kvs_getroot_cancel`.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_kvs_lookup`, :man3:`flux_future_get`, :man3:`flux_content_load`
diff --git a/doc/man3/flux_kvs_lookup.adoc b/doc/man3/flux_kvs_lookup.adoc
deleted file mode 100644
index 449ff353a41c..000000000000
--- a/doc/man3/flux_kvs_lookup.adoc
+++ /dev/null
@@ -1,239 +0,0 @@
-flux_kvs_lookup(3)
-==================
-:doctype: manpage
-
-
-NAME
-----
-flux_kvs_lookup, flux_kvs_lookupat, flux_kvs_lookup_get, flux_kvs_lookup_get_unpack, flux_kvs_lookup_get_raw, flux_kvs_lookup_get_dir, flux_kvs_lookup_get_treeobj, flux_kvs_lookup_get_symlink - look up KVS key
-
-
-SYNOPSIS
---------
- #include
-
- flux_future_t *flux_kvs_lookup (flux_t *h, const char *ns, int flags,
- const char *key);
-
- flux_future_t *flux_kvs_lookupat (flux_t *h, int flags,
- const char *key, const char *treeobj);
-
- int flux_kvs_lookup_get (flux_future_t *f, const char **value);
-
- int flux_kvs_lookup_get_unpack (flux_future_t *f, const char *fmt, ...);
-
- int flux_kvs_lookup_get_raw (flux_future_t *f,
- const void **data, int *len);
-
- int flux_kvs_lookup_get_dir (flux_future_t *f,
- const flux_kvsdir_t **dir);
-
- int flux_kvs_lookup_get_treeobj (flux_future_t *f, const char **treeobj);
-
- int flux_kvs_lookup_get_symlink (flux_future_t *f, const char **ns,
- const char **target);
-
- const char *flux_kvs_lookup_get_key (flux_future_t *f);
-
- int flux_kvs_lookup_cancel (flux_future_t *f);
-
-
-DESCRIPTION
------------
-
-The Flux Key Value Store is a general purpose distributed storage
-service used by Flux services.
-
-`flux_kvs_lookup()` sends a request to the KVS service to look up
-_key_ in namespace _ns_. It returns a `flux_future_t` object which
-acts as handle for synchronization and container for the result. The
-namespace _ns_ is optional. If set to NULL, `flux_kvs_lookup()` uses
-the default namespace, or if set, the namespace from the
-FLUX_KVS_NAMESPACE environment variable. _flags_ modifies the request
-as described below.
-
-`flux_kvs_lookupat()` is identical to `flux_kvs_lookup()` except
-_treeobj_ is a serialized RFC 11 object that references a particular
-static set of content within the KVS, effectively a snapshot.
-See `flux_kvs_lookup_get_treeobj()` below.
-
-All the functions below are variations on a common theme. First they
-complete the lookup RPC by blocking on the response, if not already received.
-Then they interpret the result in different ways. They may be called more
-than once on the same future, and they may be intermixed to probe a result
-or interpret it in different ways. Results remain valid until
-`flux_future_destroy()` is called.
-
-`flux_kvs_lookup_get()` interprets the result as a value. If the value
-has length greater than zero, a NULL is appended and it is assigned
-to _value_, otherwise NULL is assigned to _value_.
-
-`flux_kvs_lookup_get_unpack()` interprets the result as a value, which
-it decodes as JSON according to variable arguments in Jansson
-`json_unpack()` format.
-
-`flux_kvs_lookup_get_raw()` interprets the result as a value. If the value
-has length greater than zero, the value and its length are assigned to
-_buf_ and _len_, respectively. Otherwise NULL and zero are assigned.
-
-`flux_kvs_lookup_get_dir()` interprets the result as a directory,
-e.g. in response to a lookup with the FLUX_KVS_READDIR flag set.
-The directory object is assigned to _dir_.
-
-`flux_kvs_lookup_get_treeobj()` interprets the result as any RFC 11 object.
-The object in JSON-encoded form is assigned to _treeobj_. Since all
-lookup requests return an RFC 11 object of one type or another, this
-function should work on all.
-
-`flux_kvs_lookup_get_symlink()` interprets the result as a symlink target,
-e.g. in response to a lookup with the FLUX_KVS_READLINK flag set.
-The result is parsed and symlink namespace is assigned to _ns_ and
-the symlink target is assigned to _target_. If a namespace was not assigned
-to the symlink, _ns_ is set to NULL.
-
-`flux_kvs_lookup_get_key()` accesses the key argument from the original
-lookup.
-
-`flux_kvs_lookup_cancel()` cancels a stream of lookup responses
-requested with FLUX_KVS_WATCH or a waiting lookup response with
-FLUX_KVS_WAITCREATE. See FLAGS below for additional information.
-
-These functions may be used asynchronously. See `flux_future_then(3)` for
-details.
-
-
-FLAGS
------
-
-The following are valid bits in a _flags_ mask passed as an argument
-to `flux_kvs_lookup()` or `flux_kvs_lookupat()`.
-
-FLUX_KVS_READDIR::
-Look up a directory, not a value. The lookup fails if the key does
-not refer to a directory object.
-
-FLUX_KVS_READLINK::
-If key is a symlink, read the link value. The lookup fails if the key
-does not refer to a symlink object.
-
-FLUX_KVS_TREEOBJ::
-All KVS lookups return an RFC 11 tree object. This flag requests that
-they be returned without conversion. That is, a "valref" will not
-be converted to a "val" object, and a "dirref" will not be converted
-to a "dir" object. This is useful for obtaining a snapshot reference
-that can be passed to `flux_kvs_lookupat()`.
-
-FLUX_KVS_WATCH::
-After the initial response, continue to send responses to the lookup
-request each time _key_ is mentioned verbatim in a committed transaction.
-After receiving a response, `flux_future_reset()` should be used to
-consume a response and prepare for the next one. Responses continue
-until the namespace is removed, the key is removed, the lookup is
-canceled with `flux_kvs_lookup_cancel()`, or an error occurs. After
-calling `flux_kvs_lookup_cancel()`, callers should wait for the future
-to be fulfilled with an ENODATA error to ensure the cancel request has
-been received and processed.
-
-FLUX_KVS_WATCH_UNIQ::
-Specified along with FLUX_KVS_WATCH, this flag will alter watch
-behavior to only respond when _key_ is mentioned verbatim in a
-committed transaction and the value of the key has changed.
-
-FLUX_KVS_WATCH_APPEND::
-Specified along with FLUX_KVS_WATCH, this flag will alter watch
-behavior to only respond when _key_ is mentioned verbatim in a
-committed transaction and the key has been appended to. The response
-will only contain the additional appended data. Note that only data
-length is considered for appends and no guarantee is made that prior
-data hasn't been overwritten.
-
-FLUX_KVS_WATCH_FULL::
-Specified along with FLUX_KVS_WATCH, this flag will alter watch
-behavior to respond when the value of the key being watched has
-changed. Unlike FLUX_KVS_WATCH_UNIQ, the key being watched need not
-be mentioned in a transaction. This may occur under several
-scenarios, such as a parent directory being altered.
-
-FLUX_KVS_WAITCREATE::
-If a KVS key does not exist, wait for it to exist before returning.
-This flag can be specified with or without FLUX_KVS_WATCH. The lookup
-can be canceled with `flux_kvs_lookup_cancel()`. After calling
-`flux_kvs_lookup_cancel()`, callers should wait for the future to be
-fulfilled with an ENODATA error to ensure the cancel request has been
-received and processed.
-
-RETURN VALUE
-------------
-
-`flux_kvs_lookup()` and `flux_kvs_lookupat()` return a
-`flux_future_t` on success, or NULL on failure with errno set appropriately.
-
-`flux_kvs_lookup_get()`, `flux_kvs_lookup_get_unpack()`,
-`flux_kvs_lookup_get_raw()`, `flux_kvs_lookup_get_dir()`,
-`flux_kvs_lookup_get_treeobj()`, `flux_kvs_lookup_get_symlink()`,
-and `flux_kvs_lookup_cancel()` return 0 on success, or -1 on failure with
-errno set appropriately.
-
-`flux_kvs_lookup_get_key()` returns key on success, or NULL with errno
-set to EINVAL if its future argument did not come from a KVS lookup.
-
-
-ERRORS
-------
-
-EINVAL::
-One of the arguments was invalid, or FLUX_KVS_READLINK was used but
-the key does not refer to a symlink.
-
-ENOMEM::
-Out of memory.
-
-ENOENT::
-An unknown key was requested.
-
-ENOTDIR::
-FLUX_KVS_READDIR flag was set and key does NOT point to a directory.
-
-EISDIR::
-FLUX_KVS_READDIR flag was NOT set and key points to a directory.
-
-EPROTO::
-A request or response was malformed.
-
-EFBIG::
-
-ENOSYS::
-The KVS module is not loaded.
-
-ENOTSUP::
-An unknown namespace was requested or namespace was deleted.
-
-ENODATA::
-A stream of responses requested with FLUX_KVS_WATCH was terminated
-with `flux_kvs_lookup_cancel()`.
-
-EPERM::
-The user does not have instance owner capability, and a lookup was attempted
-against a KVS namespace owned by another user.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_rpc(3), flux_future_then(3), flux_kvs_set_namespace(3)
-
-https://github.com/flux-framework/rfc/blob/master/spec_11.adoc[RFC 11: Key Value Store Tree Object Format v1]
diff --git a/doc/man3/flux_kvs_lookup.rst b/doc/man3/flux_kvs_lookup.rst
new file mode 100644
index 000000000000..c30cfc88443b
--- /dev/null
+++ b/doc/man3/flux_kvs_lookup.rst
@@ -0,0 +1,237 @@
+==================
+flux_kvs_lookup(3)
+==================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_future_t *flux_kvs_lookup (flux_t *h,
+ const char *ns,
+ int flags,
+ const char *key);
+
+ flux_future_t *flux_kvs_lookupat (flux_t *h,
+ int flags,
+ const char *key,
+ const char *treeobj);
+
+ int flux_kvs_lookup_get (flux_future_t *f, const char **value);
+
+ int flux_kvs_lookup_get_unpack (flux_future_t *f,
+ const char *fmt,
+ ...);
+
+ int flux_kvs_lookup_get_raw (flux_future_t *f,
+ const void **data
+ size_t *len);
+
+ int flux_kvs_lookup_get_dir (flux_future_t *f,
+ const flux_kvsdir_t **dir);
+
+ int flux_kvs_lookup_get_treeobj (flux_future_t *f,
+ const char **treeobj);
+
+ int flux_kvs_lookup_get_symlink (flux_future_t *f,
+ const char **ns,
+ const char **target);
+
+ const char *flux_kvs_lookup_get_key (flux_future_t *f);
+
+ int flux_kvs_lookup_cancel (flux_future_t *f);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+The Flux Key Value Store is a general purpose distributed storage
+service used by Flux services.
+
+:func:`flux_kvs_lookup` sends a request to the KVS service to look up
+:var:`key` in namespace :var:`ns`. It returns a :type:`flux_future_t` object
+which acts as handle for synchronization and container for the result. The
+namespace :var:`ns` is optional. If set to NULL, :func:`flux_kvs_lookup` uses
+the default namespace, or if set, the namespace from the
+:envvar:`FLUX_KVS_NAMESPACE` environment variable. :var:`flags` modifies the
+request as described below.
+
+:func:`flux_kvs_lookupat` is identical to :func:`flux_kvs_lookup` except
+:var:`treeobj` is a serialized RFC 11 object that references a particular
+static set of content within the KVS, effectively a snapshot.
+See :func:`flux_kvs_lookup_get_treeobj` below.
+
+All the functions below are variations on a common theme. First they
+complete the lookup RPC by blocking on the response, if not already received.
+Then they interpret the result in different ways. They may be called more
+than once on the same future, and they may be intermixed to probe a result
+or interpret it in different ways. Results remain valid until
+:man3:`flux_future_destroy` is called.
+
+:func:`flux_kvs_lookup_get` interprets the result as a value. If the value
+has length greater than zero, a NULL is appended and it is assigned
+to :var:`value`, otherwise NULL is assigned to *value*.
+
+:func:`flux_kvs_lookup_get_unpack` interprets the result as a value, which
+it decodes as JSON according to variable arguments in Jansson
+:func:`json_unpack` format.
+
+:func:`flux_kvs_lookup_get_raw` interprets the result as a value. If the value
+has length greater than zero, the value and its length are assigned to
+:var:`buf` and :var:`len`, respectively. Otherwise NULL and zero are assigned.
+
+:func:`flux_kvs_lookup_get_dir` interprets the result as a directory,
+e.g. in response to a lookup with the FLUX_KVS_READDIR flag set.
+The directory object is assigned to :var:`dir`.
+
+:func:`flux_kvs_lookup_get_treeobj` interprets the result as any RFC 11 object.
+The object in JSON-encoded form is assigned to :var:`treeobj`. Since all
+lookup requests return an RFC 11 object of one type or another, this
+function should work on all.
+
+:func:`flux_kvs_lookup_get_symlink` interprets the result as a symlink target,
+e.g. in response to a lookup with the FLUX_KVS_READLINK flag set.
+The result is parsed and symlink namespace is assigned to :var:`ns` and
+the symlink target is assigned to :var:`target`. If a namespace was not assigned
+to the symlink, :var:`ns` is set to NULL.
+
+:func:`flux_kvs_lookup_get_key` accesses the key argument from the original
+lookup.
+
+:func:`flux_kvs_lookup_cancel` cancels a stream of lookup responses
+requested with FLUX_KVS_WATCH or a waiting lookup response with
+FLUX_KVS_WAITCREATE. See FLAGS below for additional information.
+
+These functions may be used asynchronously. See :man3:`flux_future_then` for
+details.
+
+
+FLAGS
+=====
+
+The following are valid bits in a :var:`flags` mask passed as an argument
+to :func:`flux_kvs_lookup` or :func:`flux_kvs_lookupat`.
+
+FLUX_KVS_READDIR
+ Look up a directory, not a value. The lookup fails if :var:`key` does
+ not refer to a directory object.
+
+FLUX_KVS_READLINK
+ If :var:`key` is a symlink, read the link value. The lookup fails if the key
+ does not refer to a symlink object.
+
+FLUX_KVS_TREEOBJ
+ All KVS lookups return an RFC 11 tree object. This flag requests that
+ they be returned without conversion. That is, a "valref" will not
+ be converted to a "val" object, and a "dirref" will not be converted
+ to a "dir" object. This is useful for obtaining a snapshot reference
+ that can be passed to :func:`flux_kvs_lookupat`.
+
+FLUX_KVS_WATCH
+ After the initial response, continue to send responses to the lookup
+ request each time :var:`key` is mentioned verbatim in a committed
+ transaction. After receiving a response, :man3:`flux_future_reset` should
+ be used to consume a response and prepare for the next one. Responses
+ continue until the namespace is removed, the key is removed, the lookup is
+ canceled with :func:`flux_kvs_lookup_cancel`, or an error occurs. After
+ calling :func:`flux_kvs_lookup_cancel`, callers should wait for the future
+ to be fulfilled with an ENODATA error to ensure the cancel request has
+ been received and processed.
+
+FLUX_KVS_WATCH_UNIQ
+ Specified along with FLUX_KVS_WATCH, this flag will alter watch
+ behavior to only respond when :var:`key` is mentioned verbatim in a
+ committed transaction and the value of the key has changed.
+
+FLUX_KVS_WATCH_APPEND
+ Specified along with FLUX_KVS_WATCH, this flag will alter watch
+ behavior to only respond when :var:`key` is mentioned verbatim in a
+ committed transaction and the key has been appended to. The
+ response will only contain the additional appended data. If the
+ value is overwritten, the lookup fails with EINVAL.
+
+FLUX_KVS_WATCH_FULL
+ Specified along with FLUX_KVS_WATCH, this flag will alter watch
+ behavior to respond when the value of the key being watched has
+ changed. Unlike FLUX_KVS_WATCH_UNIQ, the key being watched need not
+ be mentioned in a transaction. This may occur under several
+ scenarios, such as a parent directory being altered.
+
+FLUX_KVS_WAITCREATE
+ If a KVS key does not exist, wait for it to exist before returning.
+ This flag can be specified with or without FLUX_KVS_WATCH. The lookup
+ can be canceled with :func:`flux_kvs_lookup_cancel`. After calling
+ :func:`flux_kvs_lookup_cancel`, callers should wait for the future to be
+ fulfilled with an ENODATA error to ensure the cancel request has been
+ received and processed.
+
+
+RETURN VALUE
+============
+
+:func:`flux_kvs_lookup` and :func:`flux_kvs_lookupat` return a
+:type:`flux_future_t` on success, or NULL on failure with errno set
+appropriately.
+
+:func:`flux_kvs_lookup_get`, :func:`flux_kvs_lookup_get_unpack`,
+:func:`flux_kvs_lookup_get_raw`, :func:`flux_kvs_lookup_get_dir`,
+:func:`flux_kvs_lookup_get_treeobj`, :func:`flux_kvs_lookup_get_symlink`,
+and :func:`flux_kvs_lookup_cancel` return 0 on success, or -1 on failure with
+:var:`errno` set appropriately.
+
+:func:`flux_kvs_lookup_get_key` returns key on success, or NULL with
+:var:`errno` set to EINVAL if its future argument did not come from a KVS
+lookup.
+
+
+ERRORS
+======
+
+EINVAL
+ One of the arguments was invalid, or FLUX_KVS_READLINK was used but
+ the key does not refer to a symlink.
+
+ENOMEM
+ Out of memory.
+
+ENOENT
+ An unknown key was requested.
+
+ENOTDIR
+ FLUX_KVS_READDIR flag was set and key does NOT point to a directory.
+
+EISDIR
+ FLUX_KVS_READDIR flag was NOT set and key points to a directory.
+
+EPROTO
+ A request or response was malformed.
+
+EFBIG; ENOSYS
+ The KVS module is not loaded.
+
+ENOTSUP
+ An unknown namespace was requested or namespace was deleted.
+
+ENODATA
+ A stream of responses requested with FLUX_KVS_WATCH was terminated
+ with :func:`flux_kvs_lookup_cancel`.
+
+EPERM
+ The user does not have instance owner capability, and a lookup was attempted
+ against a KVS namespace owned by another user.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_11`
diff --git a/doc/man3/flux_kvs_namespace_create.adoc b/doc/man3/flux_kvs_namespace_create.adoc
deleted file mode 100644
index 4d93fcecde6e..000000000000
--- a/doc/man3/flux_kvs_namespace_create.adoc
+++ /dev/null
@@ -1,86 +0,0 @@
-flux_kvs_namespace_create(3)
-============================
-:doctype: manpage
-
-
-NAME
-----
-flux_kvs_namespace_create, flux_kvs_namespace_remove - create/remove a KVS namespace
-
-
-SYNOPSIS
---------
- #include
-
- flux_future_t *flux_kvs_namespace_create (flux_t *h,
- const char *namespace,
- uint32_t owner,
- int flags);
-
- flux_future_t *flux_kvs_namespace_remove (flux_t *h,
- const char *namespace);
-
-DESCRIPTION
------------
-
-`flux_kvs_namespace_create()` creates a KVS namespace. Within a
-namespace, users can get/put KVS values completely independent of
-other KVS namespaces. An owner of the namespace other than the
-instance owner can be chosen by setting _owner_. Otherwise, _owner_
-can be set to FLUX_USERID_UNKNOWN.
-
-`flux_kvs_namespace_remove()` removes a KVS namespace.
-
-FLAGS
------
-
-The _flags_ mask is currently unused and should be set to 0.
-
-
-RETURN VALUE
-------------
-
-`flux_kvs_namespace_create()` and `flux_kvs_namespace_remove()` return
-a `flux_future_t` on success, or NULL on failure with errno set
-appropriately.
-
-
-ERRORS
-------
-
-EINVAL::
-One of the arguments was invalid.
-
-ENOMEM::
-Out of memory.
-
-EPROTO::
-A request was malformed.
-
-ENOSYS::
-The KVS module is not loaded.
-
-EEXIST::
-The namespace already exists.
-
-ENOTSUP::
-Attempt to remove illegal namespace.
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_kvs_lookup(3), flux_kvs_commit(3)
diff --git a/doc/man3/flux_kvs_namespace_create.rst b/doc/man3/flux_kvs_namespace_create.rst
new file mode 100644
index 000000000000..ab59b3389aff
--- /dev/null
+++ b/doc/man3/flux_kvs_namespace_create.rst
@@ -0,0 +1,92 @@
+============================
+flux_kvs_namespace_create(3)
+============================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_future_t *flux_kvs_namespace_create (flux_t *h,
+ const char *namespace,
+ uint32_t owner,
+ int flags);
+
+ flux_future_t *flux_kvs_namespace_create_with (flux_t *h,
+ const char *namespace,
+ const char *rootref,
+ uint32_t owner,
+ int flags);
+
+ flux_future_t *flux_kvs_namespace_remove (flux_t *h,
+ const char *namespace);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_kvs_namespace_create` creates a KVS namespace. Within a
+namespace, users can get/put KVS values completely independent of
+other KVS namespaces. An owner of the namespace other than the
+instance owner can be chosen by setting :var:`owner`. Otherwise, :var:`owner`
+can be set to FLUX_USERID_UNKNOWN.
+
+:func:`flux_kvs_namespace_create_with` is identical to
+:func:`flux_kvs_namespace_create` but will initialize the namespace to
+the specified :var:`rootref`. This may be useful in several circumstances,
+such as initializing a namespace to an earlier checkpoint.
+
+:func:`flux_kvs_namespace_remove` removes a KVS namespace.
+
+
+FLAGS
+=====
+
+The :var:`flags` mask is currently unused and should be set to 0.
+
+
+RETURN VALUE
+============
+
+:func:`flux_kvs_namespace_create` and :func:`flux_kvs_namespace_remove` return
+a :type:`flux_future_t` on success, or NULL on failure with :var:`errno` set
+appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ One of the arguments was invalid.
+
+ENOMEM
+ Out of memory.
+
+EPROTO
+ A request was malformed.
+
+ENOSYS
+ The KVS module is not loaded.
+
+EEXIST
+ The namespace already exists.
+
+ENOTSUP
+ Attempt to remove illegal namespace.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_kvs_lookup`, :man3:`flux_kvs_commit`
diff --git a/doc/man3/flux_kvs_txn_create.adoc b/doc/man3/flux_kvs_txn_create.adoc
deleted file mode 100644
index 62daee20458b..000000000000
--- a/doc/man3/flux_kvs_txn_create.adoc
+++ /dev/null
@@ -1,140 +0,0 @@
-flux_kvs_txn_create(3)
-======================
-:doctype: manpage
-
-
-NAME
-----
-flux_kvs_txn_create, flux_kvs_txn_destroy, flux_kvs_txn_put, flux_kvs_txn_pack, flux_kvs_txn_vpack, flux_kvs_txn_mkdir, flux_kvs_txn_unlink, flux_kvs_txn_symlink, flux_kvs_txn_put_raw, flux_kvs_txn_put_treeobj - operate on a KVS transaction object
-
-
-SYNOPSIS
---------
- #include
-
- flux_kvs_txn_t *flux_kvs_txn_create (void);
-
- void flux_kvs_txn_destroy (flux_kvs_txn_t *txn);
-
- int flux_kvs_txn_put (flux_kvs_txn_t *txn, int flags,
- const char *key, const char *value);
-
- int flux_kvs_txn_pack (flux_kvs_txn_t *txn, int flags,
- const char *key, const char *fmt, ...);
-
- int flux_kvs_txn_vpack (flux_kvs_txn_t *txn, int flags,
- const char *key, const char *fmt, va_list ap);
-
- int flux_kvs_txn_mkdir (flux_kvs_txn_t *txn, int flags,
- const char *key);
-
- int flux_kvs_txn_unlink (flux_kvs_txn_t *txn, int flags,
- const char *key);
-
- int flux_kvs_txn_symlink (flux_kvs_txn_t *txn, int flags,
- const char *key, const char *ns,
- const char *target);
-
- int flux_kvs_txn_put_raw (flux_kvs_txn_t *txn, int flags,
- const char *key, const void *data, int len);
-
- int flux_kvs_txn_put_treeobj (flux_kvs_txn_t *txn, int flags,
- const char *key, const char *treeobj);
-
-
-DESCRIPTION
------------
-
-The Flux Key Value Store is a general purpose distributed storage
-service used by Flux services.
-
-`flux_kvs_txn_create()` creates a KVS transaction object that may be
-passed to `flux_kvs_commit(3)` or `flux_kvs_fence(3)`. The transaction
-consists of a list of operations that are applied to the KVS together,
-in order. The entire transaction either succeeds or fails. After commit
-or fence, the object must be destroyed with `flux_kvs_txn_destroy()`.
-
-Each function below adds a single operation to _txn_. _key_ is a
-hierarchical path name with period (".") used as path separator.
-When the transaction is committed, any existing keys or path components
-that are in conflict with the requested operation are overwritten.
-_flags_ can modify the request as described below.
-
-`flux_kvs_txn_put()` sets _key_ to a NULL terminated string _value_.
-_value_ may be NULL indicating that an empty value should be stored.
-
-`flux_kvs_txn_pack()` sets _key_ to a NULL terminated string encoded
-from a JSON object built with `json_pack()` style arguments (see below).
-`flux_kvs_txn_vpack()` is a variant that accepts a _va_list_ argument.
-
-`flux_kvs_txn_mkdir()` sets _key_ to an empty directory.
-
-`flux_kvs_txn_unlink()` removes _key_. If _key_ is a directory,
-all its contents are removed as well.
-
-`flux_kvs_txn_symlink()` sets _key_ to a symbolic link pointing to a
-namespace _ns_ and a _target_ key within that namespace. Neither _ns_
-nor _target_ must exist. The namespace _ns_ is optional, if set to
-NULL the _target_ is assumed to be in the key's current namespace.
-
-`flux_kvs_txn_put_raw()` sets _key_ to a value containing raw data
-referred to by _data_ of length _len_.
-
-`flux_kvs_txn_put_treeobj()` sets _key_ to an RFC 11 object, encoded
-as a JSON string.
-
-
-FLAGS
------
-
-The following are valid bits in a _flags_ mask passed as an argument
-to `flux_kvs_txn_put()` or `flux_kvs_txn_put_raw()`.
-
-FLUX_KVS_APPEND::
-Append value instead of overwriting it. If the key does not exist,
-it will be created with the value as the initial value.
-
-
-include::JSON_PACK.adoc[]
-
-
-RETURN VALUE
-------------
-
-`flux_kvs_txn_create()` returns a `flux_kvs_txn_t` object on success,
-or NULL on failure with errno set appropriately.
-
-`flux_kvs_txn_put()`, `flux_kvs_txn_pack()`, `flux_kvs_txn_mkdir()`,
-`flux_kvs_txn_unlink()`, `flux_kvs_txn_symlink()`, and `flux_kvs_txn_put_raw()`
-returns 0 on success, or -1 on failure with errno set appropriately.
-
-ERRORS
-------
-
-EINVAL::
-One of the arguments was invalid.
-
-ENOMEM::
-Out of memory.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_kvs_commit(3)
-
-https://github.com/flux-framework/rfc/blob/master/spec_11.adoc[RFC 11: Key Value Store Tree Object Format v1]
diff --git a/doc/man3/flux_kvs_txn_create.rst b/doc/man3/flux_kvs_txn_create.rst
new file mode 100644
index 000000000000..b83f08dc5a79
--- /dev/null
+++ b/doc/man3/flux_kvs_txn_create.rst
@@ -0,0 +1,159 @@
+======================
+flux_kvs_txn_create(3)
+======================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_kvs_txn_t *flux_kvs_txn_create (void);
+
+ void flux_kvs_txn_destroy (flux_kvs_txn_t *txn);
+
+ int flux_kvs_txn_put (flux_kvs_txn_t *txn,
+ int flags,
+ const char *key,
+ const char *value);
+
+ int flux_kvs_txn_pack (flux_kvs_txn_t *txn,
+ int flags,
+ const char *key,
+ const char *fmt,
+ ...);
+
+ int flux_kvs_txn_vpack (flux_kvs_txn_t *txn,
+ int flags,
+ const char *key,
+ const char *fmt,
+ va_list ap);
+
+ int flux_kvs_txn_mkdir (flux_kvs_txn_t *txn,
+ int flags,
+ const char *key);
+
+ int flux_kvs_txn_unlink (flux_kvs_txn_t *txn,
+ int flags,
+ const char *key);
+
+ int flux_kvs_txn_symlink (flux_kvs_txn_t *txn,
+ int flags,
+ const char *key,
+ const char *ns,
+ const char *target);
+
+ int flux_kvs_txn_put_raw (flux_kvs_txn_t *txn,
+ int flags,
+ const char *key,
+ const void *data,
+ size_t len);
+
+ int flux_kvs_txn_put_treeobj (flux_kvs_txn_t *txn,
+ int flags,
+ const char *key,
+ const char *treeobj);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+The Flux Key Value Store is a general purpose distributed storage
+service used by Flux services.
+
+:func:`flux_kvs_txn_create` creates a KVS transaction object that may be
+passed to :man3:`flux_kvs_commit` or :man3:`flux_kvs_fence`. The transaction
+consists of a list of operations that are applied to the KVS together,
+in order. The entire transaction either succeeds or fails. After commit
+or fence, the object must be destroyed with :func:`flux_kvs_txn_destroy`.
+
+Each function below adds a single operation to :var:`txn`. :var:`key` is a
+hierarchical path name with period (".") used as path separator.
+When the transaction is committed, any existing keys or path components
+that are in conflict with the requested operation are overwritten.
+:var:`flags` can modify the request as described below.
+
+:func:`flux_kvs_txn_put` sets :var:`key` to a NULL terminated string
+:var:`value`. :var:`value` may be NULL indicating that an empty value should
+be stored.
+
+:func:`flux_kvs_txn_pack` sets :var:`key` to a NULL terminated string encoded
+from a JSON object built with :func:`json_pack` style arguments (see below).
+:func:`flux_kvs_txn_vpack` is a variant that accepts a :type:`va_list` argument.
+
+:func:`flux_kvs_txn_mkdir` sets :var:`key` to an empty directory.
+
+:func:`flux_kvs_txn_unlink` removes :var:`key`. If :var:`key` is a directory,
+all its contents are removed as well.
+
+:func:`flux_kvs_txn_symlink` sets :var:`key` to a symbolic link pointing to a
+namespace :var:`ns` and a :var:`target` key within that namespace. Neither
+:var:`ns` nor :var:`target` must exist. The namespace :var:`ns` is optional,
+if set to NULL the :var:`target` is assumed to be in the key's current
+namespace.
+
+:func:`flux_kvs_txn_put_raw` sets :var:`key` to a value containing raw data
+referred to by :var:`data` of length :var:`len`.
+
+:func:`flux_kvs_txn_put_treeobj` sets :var:`key` to an RFC 11 object, encoded
+as a JSON string.
+
+
+FLAGS
+=====
+
+The following are valid bits in a :var:`flags` mask passed as an argument
+to :func:`flux_kvs_txn_put` or :func:`flux_kvs_txn_put_raw`.
+
+FLUX_KVS_APPEND
+ Append value instead of overwriting it. If the key does not exist,
+ it will be created with the value as the initial value.
+
+
+ENCODING JSON PAYLOADS
+======================
+
+.. include:: common/json_pack.rst
+
+
+RETURN VALUE
+============
+
+:func:`flux_kvs_txn_create` returns a :type:`flux_kvs_txn_t` object on success,
+or NULL on failure with :var:`errno` set appropriately.
+
+:func:`flux_kvs_txn_put`, :func:`flux_kvs_txn_pack`, :func:`flux_kvs_txn_mkdir`,
+:func:`flux_kvs_txn_unlink`, :func:`flux_kvs_txn_symlink`, and
+:func:`flux_kvs_txn_put_raw` returns 0 on success, or -1 on failure with
+:var:`errno` set appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ One of the arguments was invalid.
+
+ENOMEM
+ Out of memory.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+FLUX RFC
+========
+
+:doc:`rfc:spec_11`
+
+
+SEE ALSO
+========
+
+:man3:`flux_kvs_commit`
diff --git a/doc/man3/flux_log.adoc b/doc/man3/flux_log.adoc
deleted file mode 100644
index 1e7810637ba6..000000000000
--- a/doc/man3/flux_log.adoc
+++ /dev/null
@@ -1,128 +0,0 @@
-flux_log(3)
-===========
-:doctype: manpage
-
-
-NAME
-----
-flux_log, flux_vlog, flux_log_set_appname, flux_log_set_procid - Log messages to the Flux Message Broker
-
-
-SYNOPSIS
---------
-#include
-
-int flux_vlog (flux_t *h, int level, const char *fmt, va_list ap);
-
-int flux_log (flux_t *h, int level, const char *fmt, ...);
-
-void flux_log_set_appname (flux_t *h, const char *s);
-
-void flux_log_set_procid (flux_t *h, const char *s);
-
-DESCRIPTION
------------
-
-`flux_log()` creates RFC 5424 format log messages. The log messages
-are sent to the Flux message broker on 'h' for handling if it is
-specified. If 'h' is NULL, the log message is output to stderr.
-
-The 'level' parameter should be set to one of the syslog(3) severity
-levels, which are, in order of decreasing importance:
-
-'LOG_EMERG':: system is unusable
-'LOG_ALERT':: action must be taken immediately
-'LOG_CRIT':: critical conditions
-'LOG_ERR':: error conditions
-'LOG_WARNING':: warning conditions
-'LOG_NOTICE':: normal, but significant, condition
-'LOG_INFO':: informational message
-'LOG_DEBUG':: debug-level message
-
-When 'h' is specified, log messages are are added to the broker's
-circular buffer which can be accessed with flux-dmesg(3). From there,
-a message's disposition is up to the broker's log configuration.
-
-`flux_log_set_procid()` may be used to override the default procid,
-which is initialized to the calling process's PID.
-
-`flux_log_set_appname()` may be used to override the default
-application name, which is initialized to the value of the '__progname'
-symbol (normally the argv[0] program name).
-
-MAPPING TO SYSLOG
------------------
-
-A Flux log message is formatted as a Flux request with a "raw" payload,
-as defined by Flux RFC 3. The raw payload is formatted according to
-Internet RFC 5424.
-
-If the Flux handle 'h' is specified, the following Syslog header
-fields are set in a Flux log messages when it is created within
-`flux_log()`:
-
-PRI::
-Set to the user-specified severity level combined with the facility,
-which is hardwired to 'LOG_USER' in Flux log messages.
-
-VERSION::
-Set to 1.
-
-TIMESTAMP::
-Set to the current UTC wallclock time.
-
-HOSTNAME::
-Set to the broker rank associated with 'h'.
-
-APP-NAME::
-Set to the user-defined application name, truncated to 48 characters,
-excluding terminating NULL.
-
-PROCID::
-Set to the PID of the calling process.
-
-MSGID::
-Set to the NIL string "-".
-
-The STRUCTURED-DATA portion of the message is empty, and reserved for
-future use by Flux.
-
-The MSG portion is post-processed to ensure it contains no NULL's or non-ASCII
-characters. At this time non-ASCII UTF-8 is not supported by `flux_log()`.
-
-RETURN VALUE
-------------
-
-`flux_log()` normally returns 0 on success, or -1 if there was
-a problem building or sending the log message, with errno set.
-
-
-ERRORS
-------
-
-EPERM::
-The user does not have permission to log messages to this Flux instance.
-
-ENOMEM::
-Out of memory.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
---------
-flux-dmesg(1), flux-logger(1),
-https://tools.ietf.org/html/rfc5424[RFC 5424 The Syslog Protocol]
diff --git a/doc/man3/flux_log.rst b/doc/man3/flux_log.rst
new file mode 100644
index 000000000000..769aac272417
--- /dev/null
+++ b/doc/man3/flux_log.rst
@@ -0,0 +1,139 @@
+===========
+flux_log(3)
+===========
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ int flux_vlog (flux_t *h, int level, const char *fmt, va_list ap);
+
+ int flux_log (flux_t *h, int level, const char *fmt, ...);
+
+ void flux_log_set_appname (flux_t *h, const char *s);
+
+ void flux_log_set_procid (flux_t *h, const char *s);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_log` creates RFC 5424 format log messages. The log messages
+are sent to the Flux message broker on :var:`h` for handling if it is
+specified. If :var:`h` is NULL, the log message is output to stderr.
+
+The :var:`level` parameter should be set to one of the :linux:man3:`syslog`
+severity levels, which are, in order of decreasing importance:
+
+*LOG_EMERG*
+ system is unusable
+
+*LOG_ALERT*
+ action must be taken immediately
+
+*LOG_CRIT*
+ critical conditions
+
+*LOG_ERR*
+ error conditions
+
+*LOG_WARNING*
+ warning conditions
+
+*LOG_NOTICE*
+ normal, but significant, condition
+
+*LOG_INFO*
+ informational message
+
+*LOG_DEBUG*
+ debug-level message
+
+When :var:`h` is specified, log messages are are added to the broker's
+circular buffer which can be accessed with :man1:`flux-dmesg`. From there,
+a message's disposition is up to the broker's log configuration.
+
+:func:`flux_log_set_procid` may be used to override the default procid,
+which is initialized to the calling process's PID.
+
+:func:`flux_log_set_appname` may be used to override the default
+application name, which is initialized to the value of the :var:`__progname`
+symbol (normally the :var:`argv[0]` program name).
+
+
+MAPPING TO SYSLOG
+=================
+
+A Flux log message is formatted as a Flux request with a "raw" payload,
+as defined by Flux RFC 3. The raw payload is formatted according to
+Internet RFC 5424.
+
+If the Flux handle :var:`h` is specified, the following Syslog header
+fields are set in a Flux log messages when it is created within
+:func:`flux_log`:
+
+PRI
+ Set to the user-specified severity level combined with the facility,
+ which is hardwired to *LOG_USER* in Flux log messages.
+
+VERSION
+ Set to 1.
+
+TIMESTAMP
+ Set to the current UTC wallclock time.
+
+HOSTNAME
+ Set to the broker rank associated with *h*.
+
+APP-NAME
+ Set to the user-defined application name, truncated to 48 characters,
+ excluding terminating NULL.
+
+PROCID
+ Set to the PID of the calling process.
+
+MSGID
+ Set to the NIL string "-".
+
+The STRUCTURED-DATA portion of the message is empty, and reserved for
+future use by Flux.
+
+The MSG portion is post-processed to ensure it contains no NULL's or non-ASCII
+characters. At this time non-ASCII UTF-8 is not supported by :func:`flux_log`.
+
+
+RETURN VALUE
+============
+
+:func:`flux_log` normally returns 0 on success, or -1 if there was
+a problem building or sending the log message, with :var:`errno` set.
+
+
+ERRORS
+======
+
+EPERM
+ The user does not have permission to log messages to this Flux instance.
+
+ENOMEM
+ Out of memory.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+RFC 5424 The Syslog Protocol: https://tools.ietf.org/html/rfc5424
+
+
+SEE ALSO
+========
+
+:man1:`flux-dmesg`, :man1:`flux-logger`,
diff --git a/doc/man3/flux_msg_cmp.adoc b/doc/man3/flux_msg_cmp.adoc
deleted file mode 100644
index 474ffa065443..000000000000
--- a/doc/man3/flux_msg_cmp.adoc
+++ /dev/null
@@ -1,62 +0,0 @@
-flux_msg_cmp(3)
-===============
-:doctype: manpage
-
-
-NAME
-----
-flux_msg_cmp - match a message
-
-
-SYNOPSIS
---------
- #include
-
- struct flux_match {
- int typemask;
- uint32_t matchtag;
- char *topic_glob;
- };
-
- bool flux_msg_cmp (const flux_msg_t *msg, struct flux_match match);
-
-DESCRIPTION
------------
-
-`flux_msg_cmp()` compares _msg_ to _match_ criteria.
-
-If _match.typemask_ is nonzero, the type of the message must match
-one of the types in the mask.
-
-If _match.matchtag_ is not FLUX_MATCHTAG_NONE, the message matchtag
-must match _match.matchtag_.
-
-If _match.topic_glob_ is not NULL or an empty string, then the message topic
-string must match _match.topic_glob_ according to the rules of shell wildcards.
-
-
-RETURN VALUE
-------------
-
-`flux_msg_cmp()` returns true on a match, otherwise false.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-
-SEE ALSO
---------
-fnmatch(3)
diff --git a/doc/man3/flux_msg_cmp.rst b/doc/man3/flux_msg_cmp.rst
new file mode 100644
index 000000000000..ea1c50fdc01f
--- /dev/null
+++ b/doc/man3/flux_msg_cmp.rst
@@ -0,0 +1,55 @@
+===============
+flux_msg_cmp(3)
+===============
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ struct flux_match {
+ int typemask;
+ uint32_t matchtag;
+ char *topic_glob;
+ };
+
+ bool flux_msg_cmp (const flux_msg_t *msg, struct flux_match match);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_msg_cmp` compares :var:`msg` to :var:`match` criteria.
+
+If :var:`match.typemask` is nonzero, the type of the message must match
+one of the types in the mask.
+
+If :var:`match.matchtag` is not FLUX_MATCHTAG_NONE, the message matchtag
+must match :var:`match.matchtag`.
+
+If :var:`match.topic_glob` is not NULL or an empty string, then the message
+topic string must match :var:`match.topic_glob` according to the rules of
+shell wildcards.
+
+
+RETURN VALUE
+============
+
+:func:`flux_msg_cmp` returns true on a match, otherwise false.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:linux:man3:`fnmatch`
diff --git a/doc/man3/flux_msg_create.rst b/doc/man3/flux_msg_create.rst
new file mode 100644
index 000000000000..0f476ad05347
--- /dev/null
+++ b/doc/man3/flux_msg_create.rst
@@ -0,0 +1,73 @@
+==========================
+flux_msg_create(3)
+==========================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ flux_msg_t *flux_msg_create (int type)
+
+ flux_msg_t *flux_msg_copy (const flux_msg_t *msg, bool payload)
+
+ const flux_msg_t *flux_msg_incref (const flux_msg_t *msg)
+
+ void flux_msg_decref (const flux_msg_t *msg)
+
+ void flux_msg_destroy (flux_msg_t *msg)
+
+
+DESCRIPTION
+===========
+
+:func:`flux_msg_create` creates a :type:`flux_msg_t` of :var:`type`.
+Different types of Flux messages are defined in RFC :doc:`rfc:spec_3`. All
+messages have a starting reference count of 1.
+
+:func:`flux_msg_copy` duplicates :var:`msg`. The payload is omitted unless
+:var:`payload` is true. The initial reference count of the new message is 1.
+
+:func:`flux_msg_incref` increments the reference count of :var:`msg`
+by 1.
+
+:func:`flux_msg_decref` decrements the reference count of :var:`msg`
+by 1. When the reference count reaches 0, the message is destroyed.
+
+:func:`flux_msg_destroy` is an alias for :func:`flux_msg_decref`.
+
+RETURN VALUE
+============
+
+:func:`flux_msg_create` and :func:`flux_msg_copy` return a
+:type:`flux_msg_t` type on success. On failure, NULL is returned and
+:var:`errno` is set.
+
+:func:`flux_msg_incref` returns a constant pointer to :var:`msg` for
+convenience. On failure, NULL is returned and :var:`errno` is set.
+
+:func:`flux_msg_decref` and :func:`flux_msg_destroy` have no return value.
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+EINVAL
+ Invalid message or message type.
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_send`, :man3:`flux_respond`
diff --git a/doc/man3/flux_msg_encode.adoc b/doc/man3/flux_msg_encode.adoc
deleted file mode 100644
index 96e242be7537..000000000000
--- a/doc/man3/flux_msg_encode.adoc
+++ /dev/null
@@ -1,62 +0,0 @@
-flux_msg_encode(3)
-==================
-:doctype: manpage
-
-
-NAME
-----
-flux_msg_encode, flux_msg_decode - convert a Flux message to buffer and back again
-
-
-SYNOPSIS
---------
-#include
-
-int flux_msg_encode (const flux_msg_t *msg, void **buf, size_t *size);
-
-flux_msg_t *flux_msg_decode (void *buf, size_t size);
-
-
-DESCRIPTION
------------
-
-`flux_msg_encode()` converts _msg_ to a serialized representation,
-allocated internally and assigned to _buf_, number of bytes to _size_.
-The caller must release _buf_ with free(3).
-
-`flux_msg_decode()` performs the inverse, creating _msg_ from _buf_ and _size_.
-The caller must destroy _msg_ with flux_msg_destroy().
-
-RETURN VALUE
-------------
-
-`flux_msg_encode()` returns 0 on success. On error, -1 is returned,
-and errno is set appropriately.
-
-`flux_msg_decode()` the decoded message on success. On error, NULL
-is returned, and errno is set appropriately.
-
-ERRORS
-------
-
-EINVAL::
-Some arguments were invalid.
-
-ENOMEM::
-Out of memory.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
diff --git a/doc/man3/flux_msg_encode.rst b/doc/man3/flux_msg_encode.rst
new file mode 100644
index 000000000000..57c8d8d4359b
--- /dev/null
+++ b/doc/man3/flux_msg_encode.rst
@@ -0,0 +1,57 @@
+==================
+flux_msg_encode(3)
+==================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ int flux_msg_encode (const flux_msg_t *msg,
+ void **buf,
+ size_t *size);
+
+ flux_msg_t *flux_msg_decode (void *buf, size_t size);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_msg_encode` converts :var:`msg` to a serialized representation,
+allocated internally and assigned to :var:`buf`, number of bytes to :var:`size`.
+The caller must release :var:`buf` with :linux:man3:`free`.
+
+:func:`flux_msg_decode` performs the inverse, creating :var:`msg` from
+:var:`buf` and :var:`size`. The caller must destroy :var:`msg` with
+:func:`flux_msg_destroy`.
+
+
+RETURN VALUE
+============
+
+:func:`flux_msg_encode` returns 0 on success. On error, -1 is returned,
+and :var:`errno` is set appropriately.
+
+:func:`flux_msg_decode` the decoded message on success. On error, NULL
+is returned, and :var:`errno` is set appropriately.
+
+
+ERRORS
+======
+
+EINVAL
+ Some arguments were invalid.
+
+ENOMEM
+ Out of memory.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
diff --git a/doc/man3/flux_msg_handler_addvec.adoc b/doc/man3/flux_msg_handler_addvec.adoc
deleted file mode 100644
index c1cd64dbfa55..000000000000
--- a/doc/man3/flux_msg_handler_addvec.adoc
+++ /dev/null
@@ -1,83 +0,0 @@
-flux_msg_handler_addvec(3)
-==========================
-:doctype: manpage
-
-
-NAME
-----
-flux_msg_handler_addvec,
-flux_msg_handler_delvec - bulk add/remove message handlers
-
-
-SYNOPSIS
---------
- #include
-
- struct flux_msg_handler_spec {
- int typemask;
- const char *topic_glob;
- flux_msg_handler_f cb;
- uint32_t rolemask;
- };
-
- int flux_msg_handler_addvec (flux_t *h,
- const struct flux_msg_handler_spec tab[],
- void *arg,
- flux_msg_handler_t **handlers[]);
-
- void flux_msg_handler_delvec (flux_msg_handler_t *handlers[]);
-
-
-DESCRIPTION
------------
-
-`flux_msg_handler_addvec()` creates and starts an array of message handlers,
-terminated by FLUX_MSGHANDLER_TABLE_END. The new message handler objects
-are assigned to an internally allocated array, returned in _handlers_.
-The last entry in the array is set to NULL.
-
-`flux_msg_handler_delvec()` stops and destroys an array of message handlers
-returned from `flux_msg_handler_addvec()`.
-
-These functions are convenience functions which call
-`flux_msg_handler_create(3)`, `flux_msg_handler_start(3)`; and
-`flux_msg_handler_stop(3)`, `flux_msg_handler_destroy(3)` on each element
-of the array, respectively.
-
-If `flux_msg_handler_addvec()` encounters an error creating a message
-handler, all previously created message handlers in the array are destroyed
-before an error is returned.
-
-
-RETURN VALUE
-------------
-
-`flux_msg_handler_addvec()` returns zero on success.
-On error, -1 is returned, and errno is set appropriately.
-
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_msg_handler_create(3)
diff --git a/doc/man3/flux_msg_handler_addvec.rst b/doc/man3/flux_msg_handler_addvec.rst
new file mode 100644
index 000000000000..6d28f8100312
--- /dev/null
+++ b/doc/man3/flux_msg_handler_addvec.rst
@@ -0,0 +1,74 @@
+==========================
+flux_msg_handler_addvec(3)
+==========================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ struct flux_msg_handler_spec {
+ int typemask;
+ const char *topic_glob;
+ flux_msg_handler_f cb;
+ uint32_t rolemask;
+ };
+
+ int flux_msg_handler_addvec (flux_t *h,
+ const struct flux_msg_handler_spec tab[],
+ void *arg,
+ flux_msg_handler_t **handlers[]);
+
+ void flux_msg_handler_delvec (flux_msg_handler_t *handlers[]);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_msg_handler_addvec` creates and starts an array of message handlers,
+terminated by FLUX_MSGHANDLER_TABLE_END. The new message handler objects
+are assigned to an internally allocated array, returned in :var:`handlers`.
+The last entry in the array is set to NULL.
+
+:func:`flux_msg_handler_delvec` stops and destroys an array of message handlers
+returned from :func:`flux_msg_handler_addvec`.
+
+These functions are convenience functions which call
+:man3:`flux_msg_handler_create`, :man3:`flux_msg_handler_start`; and
+:man3:`flux_msg_handler_stop`, :man3:`flux_msg_handler_destroy` on each element
+of the array, respectively.
+
+If :func:`flux_msg_handler_addvec` encounters an error creating a message
+handler, all previously created message handlers in the array are destroyed
+before an error is returned.
+
+
+RETURN VALUE
+============
+
+:func:`flux_msg_handler_addvec` returns zero on success.
+On error, -1 is returned, and :var:`errno` is set appropriately.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_msg_handler_create`
diff --git a/doc/man3/flux_msg_handler_create.adoc b/doc/man3/flux_msg_handler_create.adoc
deleted file mode 100644
index c42dd9ee98b5..000000000000
--- a/doc/man3/flux_msg_handler_create.adoc
+++ /dev/null
@@ -1,120 +0,0 @@
-flux_msg_handler_create(3)
-==========================
-:doctype: manpage
-
-
-NAME
-----
-flux_msg_handler_create, flux_msg_handler_destroy,
-flux_msg_handler_start, flux_msg_handler_stop - manage message handlers
-
-
-SYNOPSIS
---------
- #include
-
- typedef void (*flux_msg_handler_f)(flux_t *h,
- flux_msg_handler_t *mh,
- const flux_msg_t *msg,
- void *arg);
-
- flux_msg_handler_t *
- flux_msg_handler_create (flux_t *h,
- const struct flux_match match,
- flux_msg_handler_f callback,
- void *arg);
-
- void flux_msg_handler_destroy (flux_msg_handler_t *mh);
-
- void flux_msg_handler_start (flux_msg_handler_t *mh);
-
- void flux_msg_handler_stop (flux_msg_handler_t *mh);
-
-
-DESCRIPTION
------------
-
-`flux_msg_handler_create()` registers _callback_ to be invoked when
-a message meeting _match_ criteria, as described in `flux_msg_cmp(3)`,
-is received on Flux broker handle _h_.
-
-The message handler must be started with `flux_msg_handler_start()` in
-order to receive messages. Conversely, `flux_msg_handler_stop()` causes
-the message handler to stop receiving messages. Starting and stopping
-are idempotent operations.
-
-The handle _h_ is monitored for FLUX_POLLIN events on the flux_reactor_t
-associated with the handle as described in `flux_set_reactor(3)`.
-This internal "handle watcher" is started when the first message handler
-is started, and stopped when the last message handler is stopped.
-
-Messages arriving on _h_ are internally read and dispatched to matching
-message handlers. If multiple handlers match the message, the following
-rules apply:
-
-FLUX_MSGTYPE_REQUEST::
-Requests are first delivered to a message handler whose match.topic_glob
-is set to an exact string match of the message topic glob. The most recently
-registered of these takes precedence. If an exact match is unavailable,
-the message is delivered to the most recently registered message handler
-for which `flux_msg_cmp()` returns true. If there is no match, an ENOSYS
-response is automatically generated by the dispatcher.
-
-FLUX_MSGTYPE_RESPONSE::
-Responses are first delivered to a matching RPC response handler
-(match.matchtag != FLUX_MATCHTAG_NONE). If an RPC response handler
-does not match, responses are delivered to the most recently registered
-message handler for which `flux_msg_cmp()` returns true. If there is no
-match, the response is discarded.
-
-FLUX_MSGTYPE_EVENT::
-Events are delivered to _all_ matching message handlers.
-
-`flux_msg_handler_destroy()` destroys a handler, after internally
-stopping it.
-
-
-CAVEATS
--------
-
-FLUX_MSGTYPE_EVENT messages are received on the handle only as
-requested by `flux_event_subscribe(3)`.
-
-`flux-broker(1)` only routes FLUX_MSGTYPE_REQUEST messages to comms
-modules according to their registered service name, which is the same as
-the module name. Other handle instances such as those on the local connector
-cannot yet receive requests.
-
-
-RETURN VALUE
-------------
-
-`flux_msg_handler_create()` returns a flux_msg_handler_t object on success.
-On error, NULL is returned, and errno is set appropriately.
-
-
-ERRORS
-------
-
-ENOMEM::
-Out of memory.
-
-
-AUTHOR
-------
-This page is maintained by the Flux community.
-
-
-RESOURCES
----------
-Github:
-
-
-COPYRIGHT
----------
-include::COPYRIGHT.adoc[]
-
-
-SEE ALSO
----------
-flux_get_reactor(3), flux_reactor_start(3), flux_msg_cmp(3)
diff --git a/doc/man3/flux_msg_handler_create.rst b/doc/man3/flux_msg_handler_create.rst
new file mode 100644
index 000000000000..c32e00897d8c
--- /dev/null
+++ b/doc/man3/flux_msg_handler_create.rst
@@ -0,0 +1,116 @@
+==========================
+flux_msg_handler_create(3)
+==========================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ typedef void (*flux_msg_handler_f)(flux_t *h,
+ flux_msg_handler_t *mh,
+ const flux_msg_t *msg,
+ void *arg);
+
+ flux_msg_handler_t *flux_msg_handler_create (
+ flux_t *h,
+ const struct flux_match match,
+ flux_msg_handler_f callback,
+ void *arg);
+
+ void flux_msg_handler_destroy (flux_msg_handler_t *mh);
+
+ void flux_msg_handler_start (flux_msg_handler_t *mh);
+
+ void flux_msg_handler_stop (flux_msg_handler_t *mh);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+:func:`flux_msg_handler_create` registers :var:`callback` to be invoked when
+a message meeting :var:`match` criteria, as described in :man3:`flux_msg_cmp`,
+is received on Flux broker handle :var:`h`.
+
+The message handler must be started with :func:`flux_msg_handler_start` in
+order to receive messages. Conversely, :func:`flux_msg_handler_stop` causes
+the message handler to stop receiving messages. Starting and stopping
+are idempotent operations.
+
+The handle :var:`h` is monitored for FLUX_POLLIN events on the
+:type:`flux_reactor_t` associated with the handle as described in
+:man3:`flux_set_reactor`. This internal "handle watcher" is started when the
+first message handler is started, and stopped when the last message handler
+is stopped.
+
+Messages arriving on :var:`h` are internally read and dispatched to matching
+message handlers. If multiple handlers match the message, the following
+rules apply:
+
+FLUX_MSGTYPE_REQUEST
+ Requests are first delivered to a message handler whose
+ :var:`match.topic_glob` is set to an exact string match of the message
+ topic glob. The most recently registered of these takes precedence. If an
+ exact match is unavailable, the message is delivered to the most recently
+ registered message handler for which :man3:`flux_msg_cmp` returns true. If
+ there is no match, an ENOSYS response is automatically generated by the
+ dispatcher.
+
+FLUX_MSGTYPE_RESPONSE
+ Responses are first delivered to a matching RPC response handler
+ (:var:`match.matchtag` != FLUX_MATCHTAG_NONE). If an RPC response handler
+ does not match, responses are delivered to the most recently registered
+ message handler for which :man3:`flux_msg_cmp` returns true. If there is no
+ match, the response is discarded.
+
+FLUX_MSGTYPE_EVENT
+ Events are delivered to *all* matching message handlers.
+
+:func:`flux_msg_handler_destroy` destroys a handler, after internally
+stopping it.
+
+
+CAVEATS
+=======
+
+Although it is possible to register a message handler in a given :type:`flux_t`
+handle for any topic string, :man1:`flux-broker` does not automatically route
+matching requests or events to the handle.
+
+Requests are only routed if the handle has registered a matching service
+with :man3:`flux_service_register`, or for broker modules only, the service
+matches the module name.
+
+Events are only routed if the topic matches a subscription registered
+with :man3:`flux_event_subscribe`.
+
+
+RETURN VALUE
+============
+
+:func:`flux_msg_handler_create` returns a :type:`flux_msg_handler_t` object on
+success. On error, NULL is returned, and :var:`errno` is set appropriately.
+
+
+ERRORS
+======
+
+ENOMEM
+ Out of memory.
+
+
+RESOURCES
+=========
+
+.. include:: common/resources.rst
+
+
+SEE ALSO
+========
+
+:man3:`flux_get_reactor`, :man3:`flux_reactor_run`, :man3:`flux_msg_cmp`
diff --git a/doc/man3/flux_msg_has_flag.rst b/doc/man3/flux_msg_has_flag.rst
new file mode 100644
index 000000000000..d9be92288a7c
--- /dev/null
+++ b/doc/man3/flux_msg_has_flag.rst
@@ -0,0 +1,134 @@
+====================
+flux_msg_has_flag(3)
+====================
+
+.. default-domain:: c
+
+SYNOPSIS
+========
+
+.. code-block:: c
+
+ #include
+
+ bool flux_msg_has_flag (const flux_msg_t *msg, int flag);
+ int flux_msg_set_flag (flux_msg_t *msg, int flag);
+ int flux_msg_clear_flag (flux_msg_t *msg, int flag);
+
+ int flux_msg_set_private (flux_msg_t *msg);
+ bool flux_msg_is_private (const flux_msg_t *msg);
+
+ int flux_msg_set_streaming (flux_msg_t *msg);
+ bool flux_msg_is_streaming (const flux_msg_t *msg);
+
+ int flux_msg_set_noresponse (flux_msg_t *msg);
+ bool flux_msg_is_noresponse (const flux_msg_t *msg);
+
+Link with :command:`-lflux-core`.
+
+DESCRIPTION
+===========
+
+These functions manipulate the Flux `MESSAGE FLAGS`_.
+
+:func:`flux_msg_has_flag` returns true if any flags in the :var:`flag` bitmask
+are set in :var:`msg`.
+
+:func:`flux_msg_set_flag` sets all flags in the :var:`flag` bitmask in
+:var:`msg`.
+
+:func:`flux_msg_clear_flag` clears all flags in the :var:`flag` bitmask in
+:var:`msg`.
+
+:func:`flux_msg_is_private` returns true if FLUX_MSGFLAG_PRIVATE is set
+in :var:`msg`.
+
+:func:`flux_msg_set_private` sets FLUX_MSGFLAG_PRIVATE in :var:`msg`.
+
+:func:`flux_msg_is_streaming` returns true if FLUX_MSGFLAG_STREAMING is set
+in :var:`msg`.
+
+:func:`flux_msg_set_streaming` sets FLUX_MSGFLAG_STREAMING in :var:`msg`.
+
+:func:`flux_msg_is_noresponse` returns true if FLUX_MSGFLAG_NORESPONSE is set
+in :var:`msg`.
+
+:func:`flux_msg_set_noresponse` sets FLUX_MSGFLAG_NORESPONSE in :var:`msg`.
+
+MESSAGE FLAGS
+=============
+
+The following message flags are defined by :doc:`RFC 3 `:
+
+FLUX_MSGFLAG_TOPIC
+ The message has a topic string. This flag is updated by
+ :func:`flux_msg_set_topic`.
+
+FLUX_MSGFLAG_PAYLOAD
+ The message has a payload. This flag is updated by
+ :func:`flux_msg_set_payload`, :func:`flux_msg_pack`, etc.
+
+FLUX_MSGFLAG_NORESPONSE
+ The request message should not be sent a response. This flag is set
+ by :func:`flux_rpc` when the FLUX_RPC_NORESPONSE flag is set.
+
+FLUX_MSGFLAG_ROUTE
+ The request or response message has a route stack, although it may be empty.
+ This flag is updated by :func:`flux_msg_route_enable` and
+ :func:`flux_msg_route_disable`.
+
+FLUX_MSGFLAG_UPSTREAM
+ Force the broker to route a request upstream (towards the root on the tree
+ based overlay network) relative to the sending rank. In other words,
+ prevent the request from being handled locally. The message :var:`nodeid`
+ is interpreted as the *sending* rank when this flag is set.
+
+FLUX_MSGFLAG_PRIVATE
+ The event message should only be forwarded to connections authenticated
+ as the instance owner or the message :var:`userid`.
+
+FLUX_MSGFLAG_STREAMING
+ The request or response message is part of a streaming RPC, as defined
+ by :doc:`RFC 6